Używam ViewPagera zgodnego z wersją 4 w systemie Android. Moja FragmentActivity zawiera zbiór danych, które mają być wyświetlane na różne sposoby na różnych stronach w moim ViewPager. Do tej pory mam tylko 3 wystąpienia tego samego ListFragment, ale w przyszłości będę miał 3 wystąpienia różnych ListFragmentów. ViewPager znajduje się na pionowym ekranie telefonu, listy nie są obok siebie.
Teraz przycisk na ListFragment uruchamia oddzielne działanie na całej stronie (za pośrednictwem FragmentActivity), które zwraca, a FragmentActivity modyfikuje dane, zapisuje je, a następnie próbuje zaktualizować wszystkie widoki w swoim ViewPager. To tutaj utknąłem.
public class ProgressMainActivity extends FragmentActivity
{
MyAdapter mAdapter;
ViewPager mPager;
@Override
public void onCreate(Bundle savedInstanceState)
{
...
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager = (ViewPager) findViewById(R.id.viewpager);
mPager.setAdapter(mAdapter);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
...
updateFragments();
...
}
public void updateFragments()
{
//Attempt 1:
//mAdapter.notifyDataSetChanged();
//mPager.setAdapter(mAdapter);
//Attempt 2:
//HomeListFragment fragment = (HomeListFragment) getSupportFragmentManager().findFragmentById(mAdapter.fragId[0]);
//fragment.updateDisplay();
}
public static class MyAdapter extends FragmentPagerAdapter implements
TitleProvider
{
int[] fragId = {0,0,0,0,0};
public MyAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public String getTitle(int position){
return titles[position];
}
@Override
public int getCount(){
return titles.length;
}
@Override
public Fragment getItem(int position)
{
Fragment frag = HomeListFragment.newInstance(position);
//Attempt 2:
//fragId[position] = frag.getId();
return frag;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE; //To make notifyDataSetChanged() do something
}
}
public class HomeListFragment extends ListFragment
{
...
public static HomeListFragment newInstance(int num)
{
HomeListFragment f = new HomeListFragment();
...
return f;
}
...
Teraz, jak widać, moją pierwszą próbą było powiadomienieDataSetChanged na całym FragmentPagerAdapter, co pokazało, że czasami aktualizuje dane, ale w innych otrzymałem wyjątek IllegalStateException: nie można wykonać tej akcji po onSaveInstanceState.
Moja druga próba wywołała próbę wywołania funkcji aktualizacji w moim ListFragment, ale getId w getItem zwróciło 0. Zgodnie z dokumentacją, którą wypróbowałem
pozyskiwanie odniesienia do fragmentu z FragmentManager za pomocą findFragmentById () lub findFragmentByTag ()
ale nie znam tagu ani identyfikatora moich fragmentów! Mam android: id = "@ + id / viewpager" dla ViewPager i android: id = "@ android: id / list" dla mojego ListView w układzie ListFragment, ale nie sądzę, żeby były przydatne.
W jaki więc sposób mogę: a) bezpiecznie zaktualizować cały ViewPager za jednym razem (najlepiej przywracając użytkownika do strony, na której był wcześniej) - nie ma problemu, aby użytkownik zobaczył zmianę widoku. Lub najlepiej b) Wywołaj funkcję w każdym ListFragment, którego dotyczy problem, aby ręcznie zaktualizować ListView.
Każda pomoc zostanie przyjęta z wdzięcznością!
null
za fragment.FragmentPagerAdaper
ale nie działaFragmentStatePagerAdaper
(Fragment.getTag()
zawsze wracająnull
.Odpowiedź Barkside działa,
FragmentPagerAdapter
ale nie działaFragmentStatePagerAdapter
, ponieważ nie ustawia tagów na fragmentach, do których przekazujeFragmentManager
.Ze
FragmentStatePagerAdapter
wydaje możemy dostać się za pomocą swojegoinstantiateItem(ViewGroup container, int position)
połączenia. Zwraca odniesienie do fragmentu na pozycjiposition
. JeśliFragmentStatePagerAdapter
już zawiera odniesienie do danego fragmentu,instantiateItem
po prostu zwraca odniesienie do tego fragmentu i nie wywołujegetItem()
ponownego utworzenia jego wystąpienia.Więc przypuśćmy, że aktualnie patrzę na fragment # 50 i chcę uzyskać dostęp do fragmentu # 49. Ponieważ są blisko, istnieje duża szansa, że wystąpienie # 49 zostanie już utworzone. Więc,
źródło
FragmentStatePagerAdapter
, użycie powyższego kodu za.instantiateItem(viewPager, viewPager.getCurrentItem());
(aby pozbyć się 49) zgodnie z propozycją @ mblackwell8 działa idealnie.instantiateItem
powinny być otoczone przezstartUpdate
/finishUpdate
call. szczegóły są w mojej odpowiedzi na podobne pytanie: stackoverflow.com/questions/14035090/…OK, myślę, że znalazłem sposób na wykonanie prośby b) w moim własnym pytaniu, więc podzielę się nią z korzyścią dla innych. Znacznik fragmentów wewnątrz ViewPager ma postać
"android:switcher:VIEWPAGER_ID:INDEX"
, gdzieVIEWPAGER_ID
jestR.id.viewpager
układem XML, a INDEX to pozycja w viewpager. Więc jeśli pozycja jest znana (np. 0), mogę wykonać wupdateFragments()
:Nie mam pojęcia, czy to właściwy sposób, ale wystarczy, dopóki nie zaproponuje się czegoś lepszego.
źródło
makeFragmentName
używaną do generowania tagu, którego można użyć zamiast nieco mniejHomeListFragment fragment = (HomeListFragment) getSupportFragmentManager().findFragmentByTag(FragmentPagerAdapter.makeFragmentName(R.id.viewpager, 0));
makeFragmentName
jestprivate static
metodą, więc nie możesz uzyskać do niej dostępu.Jeśli o mnie chodzi, drugie rozwiązanie na poniższej stronie, śledzące wszystkie „aktywne” strony z fragmentami, jest lepsze: http://tamsler.blogspot.nl/2011/11/android-viewpager-and-fragments-part -ii.html
Odpowiedź z barkside jest dla mnie zbyt hakerska.
śledzisz wszystkie „aktywne” strony fragmentów. W takim przypadku możesz śledzić strony fragmentów w FragmentStatePagerAdapter, który jest używany przez ViewPager.
Aby uniknąć utrzymywania odniesienia do „nieaktywnych” stron fragmentów, musimy zaimplementować metodę zniszczItem (...) FragmentStatePagerAdapter:
... a kiedy potrzebujesz uzyskać dostęp do aktualnie widocznej strony, zadzwoń:
... gdzie metoda getFragment (int) MyAdapter wygląda następująco:
"
źródło
W porządku, po przetestowaniu metody przy użyciu @barkside powyżej, nie mogłem zmusić jej do pracy z moją aplikacją. Potem przypomniałem sobie, że aplikacja IOSched2012 również używa a
viewpager
i tam właśnie znalazłem swoje rozwiązanie. Nie używa żadnych identyfikatorów fragmentów ani tagów, ponieważ nie są one przechowywaneviewpager
w łatwo dostępny sposób.Oto ważne części z aplikacji IOSched HomeActivity. Zwróć szczególną uwagę na komentarz , bo w nim tkwi klucz .:
I przechowuj swoje instancje
Fragments
w następującyFragmentPagerAdapter
sposób:Pamiętaj też, aby pilnować swoich
Fragment
połączeń w ten sposób:źródło
getItem()
braku wywołania po odtworzeniu rodzica z powodu zmiany cyklu życia. Zobacz stackoverflow.com/a/24662049/236743 . W tym przykładzie jest to częściowo chronione przez jeden fragment, ale nie przez dwa pozostałeMożesz skopiować
FragmentPagerAdapter
i zmodyfikować kod źródłowy, dodaćgetTag()
metodęna przykład
następnie rozszerz go, zastąp te abstrakcyjne metody, nie musisz się bać zmiany grupy Androida
FragmentPageAdapter
kod źródłowy w przyszłościźródło
Działa również bez problemów:
gdzieś w układzie fragmentu strony:
we fragmencie onCreateView ():
i metoda zwracania fragmentu z ViewPager, jeśli istnieje:
źródło
Alternatywnie możesz nadpisać
setPrimaryItem
metodę zFragmentPagerAdapter
poniższego:źródło
Chcę przedstawić swoje podejście na wypadek, gdyby mogło pomóc komukolwiek innemu:
Oto mój adapter do pagera:
W swojej działalności mam:
Następnie, aby uzyskać bieżący fragment, robię:
źródło
To jest moje rozwiązanie, ponieważ nie muszę śledzić moich kart i i tak muszę je wszystkie odświeżyć.
źródło