Nie mogę zaktualizować zawartości w ViewPager.
Jakie jest prawidłowe użycie metod instantiateItem () i getItem () w klasie FragmentPagerAdapter?
Używałem tylko metody getItem () do tworzenia instancji i zwracania moich fragmentów:
@Override
public Fragment getItem(int position) {
return new MyFragment(context, paramters);
}
To działało dobrze. Tyle że nie mogę zmienić treści.
Więc znalazłem to: ViewPager PagerAdapter nie aktualizuje widoku
„Moje podejście polega na użyciu metody setTag () dla dowolnego utworzonego widoku w metodzie instantiateItem ()”
Teraz chcę zaimplementować instantiateItem (), aby to zrobić. Ale nie wiem, co muszę zwrócić (typ to Object) i jaka jest relacja z getItem (pozycja int)?
Przeczytałem referencję :
public abstract Fragment getItem (pozycja wewnętrzna)
Zwraca Fragment powiązany z określoną pozycją.
public Object instantiateItem (kontener ViewGroup, pozycja int)
Utwórz stronę dla danej pozycji. Adapter jest odpowiedzialny za dodanie widoku do podanego tutaj kontenera, ale musi tylko upewnić się, że zostanie to zrobione do czasu powrotu z finishUpdate (ViewGroup). Parametry
kontener Zawierający widok, w którym strona będzie wyświetlana. pozycja Pozycja strony, która ma zostać utworzona.
Zwroty
Zwraca obiekt reprezentujący nową stronę. To nie musi być Widok, ale może to być inny kontener strony.
ale wciąż tego nie rozumiem.
Oto mój kod. Korzystam z pakietu wsparcia v4.
ViewPagerTest
public class ViewPagerTest extends FragmentActivity {
private ViewPager pager;
private MyFragmentAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager1);
pager = (ViewPager)findViewById(R.id.slider);
String[] data = {"page1", "page2", "page3", "page4", "page5", "page6"};
adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
pager.setAdapter(adapter);
((Button)findViewById(R.id.button)).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
reload();
}
});
}
private void reload() {
String[] data = {"changed1", "changed2", "changed3", "changed4", "changed5", "changed6"};
//adapter = new MyFragmentAdapter(getSupportFragmentManager(), 6, this, data);
adapter.setData(data);
adapter.notifyDataSetChanged();
pager.invalidate();
//pager.setCurrentItem(0);
}
}
MyFragmentAdapter
class MyFragmentAdapter extends FragmentPagerAdapter {
private int slideCount;
private Context context;
private String[] data;
public MyFragmentAdapter(FragmentManager fm, int slideCount, Context context, String[] data) {
super(fm);
this.slideCount = slideCount;
this.context = context;
this.data = data;
}
@Override
public Fragment getItem(int position) {
return new MyFragment(data[position], context);
}
@Override
public int getCount() {
return slideCount;
}
public void setData(String[] data) {
this.data = data;
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
MyFragment
public final class MyFragment extends Fragment {
private String text;
public MyFragment(String text, Context context) {
this.text = text;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.slide, null);
((TextView)view.findViewById(R.id.text)).setText(text);
return view;
}
}
Oto także ktoś z podobnym problemem, brak odpowiedzi http://www.mail-archive.com/[email protected]/msg200477.html
Odpowiedzi:
Korzystając z FragmentPagerAdapter lub FragmentStatePagerAdapter najlepiej radzić sobie wyłącznie z
getItem()
dotykiem, a nie dotykać goinstantiateItem()
wcale. InterfejsinstantiateItem()
-destroyItem()
-isViewFromObject()
w PagerAdapter jest interfejsem niższego poziomu, którego FragmentPagerAdapter używa do implementacji znacznie prostszegogetItem()
interfejsu.Zanim przejdę do tego, powinienem to wyjaśnić
Wcześniejsza wersja tej odpowiedzi popełniła błąd przy użyciu FragmentPagerAdapter w swoim przykładzie - to nie zadziała, ponieważ FragmentPagerAdapter nigdy nie niszczy fragmentu po jego pierwszym wyświetleniu.
Nie polecam
setTag()
ifindViewWithTag()
Obejście zawarte w poście ty powiązane. Jak odkryłeś, używaniesetTag()
ifindViewWithTag()
nie działa z fragmentami, więc nie jest to dobre dopasowanie.Właściwym rozwiązaniem jest zastąpienie
getItemPosition()
. PonotifyDataSetChanged()
wywołaniu ViewPager wywołujegetItemPosition()
wszystkie elementy w adapterze, aby sprawdzić, czy należy je przenieść w inne miejsce, czy usunąć.Domyślnie
getItemPosition()
zwracaPOSITION_UNCHANGED
, co oznacza: „Ten obiekt jest w porządku tam, gdzie jest, nie niszcz go ani nie usuwaj”. ZwróceniePOSITION_NONE
rozwiązuje problem, mówiąc: „Ten obiekt nie jest już elementem, który wyświetlam, usuń go”. Dzięki temu usuwa i odtwarza każdy element w adapterze.Jest to całkowicie uzasadniona poprawka! Ta poprawka sprawia, że replaceDataSetChanged zachowuje się jak zwykły adapter bez recyklingu widoku. Jeśli zastosujesz tę poprawkę, a wydajność będzie satysfakcjonująca, możesz wziąć udział w wyścigach. Zadanie wykonane.
Jeśli potrzebujesz lepszej wydajności, możesz skorzystać z bardziej zaawansowanej
getItemPosition()
implementacji. Oto przykład pagera tworzącego fragmenty z listy ciągów:Dzięki tej implementacji będą wyświetlane tylko fragmenty zawierające nowe tytuły. Fragmenty zawierające tytuły, które wciąż znajdują się na liście, zostaną zamiast tego przeniesione do nowej pozycji na liście, a fragmenty z tytułami, których już nie ma na liście, zostaną zniszczone.
Co jeśli fragment nie został ponownie utworzony, ale i tak wymaga aktualizacji? Aktualizacje żywego fragmentu najlepiej jest obsługiwać przez sam fragment. W końcu to zaleta posiadania fragmentu - jest to jego własny kontroler. Fragment może dodać detektor lub obserwator do innego obiektu w
onCreate()
, a następnie usunąć goonDestroy()
, tym samym zarządzając samymi aktualizacjami. Nie musisz umieszczać całego kodu aktualizacji,getItem()
tak jak w adapterze dla ListView lub innych typów AdapterView.Ostatnia rzecz - tylko dlatego, że FragmentPagerAdapter nie niszczy fragmentu, nie oznacza, że getItemPosition jest całkowicie bezużyteczny w FragmentPagerAdapter. Nadal możesz użyć tego wywołania zwrotnego, aby zmienić kolejność swoich fragmentów w ViewPager. Jednak nigdy nie usunie ich całkowicie z narzędzia FragmentManager.
źródło
FragmentStatePagerAdapter
widzę, że usuwa mój fragment i tworzy nowe wystąpienie. Ale nowa instancja otrzymuje pakiet saveInstanceState ze stanem starego fragmentu. Jak mogę całkowicie zniszczyć fragment, aby pakiet był pusty po ponownym utworzeniu?Zamiast powrocie
POSITION_NONE
zgetItemPosition()
powodując pełny widok rekreacji, to zrobić:Twoje fragmenty powinny implementować
UpdateableFragment
interfejs:i interfejs:
Twoja klasa danych:
źródło
Fragment
dynamicznie, spójrz: stackoverflow.com/questions/19891828/...d page on refreshes the 1-st page only after swiping pages? thw 2
d jest zawsze pusta. dziękidla tych, którzy wciąż napotykają ten sam problem, z którym miałem do czynienia, kiedy mam
ViewPager
7 fragmentów. domyślnie dla tych fragmentów ładowana jest treść angielska zAPI
usługi, ale tutaj problem polega na tym, że chcę zmienić język z działania ustawień i po zakończeniu działania ustawień chcęViewPager
w działaniu głównym odświeżyć fragmenty, aby dopasować wybór języka od użytkownika i załadować treść w języku arabskim, jeśli użytkownik wybierze tutaj język arabski, co zrobiłem po raz pierwszy1- Musisz użyć FragmentStatePagerAdapter, jak wspomniano powyżej.
2- na mainActivity i przesłaniam onResume i wykonałem następujące czynności
3-i zastąpiło
getItemPosition()
w mPagerAdapter i sprawiło, że zwróciłoPOSITION_NONE
.działa jak urok
źródło
Zetknąłem się z tym problemem i ostatecznie go rozwiązałem dzisiaj, więc zapisuję to, czego się nauczyłem i mam nadzieję, że będzie on pomocny dla kogoś, kto jest nowy w Androidzie
ViewPager
i będzie aktualizował się w tym momencie. UżywamFragmentStatePagerAdapter
na poziomie API 17 i obecnie mam tylko 2 fragmenty. Myślę, że musi być coś nie tak, popraw mnie, dziękuję.Dane szeregowe należy załadować do pamięci. Można to zrobić za pomocą
CursorLoader
/AsyncTask
/Thread
. To, czy zostanie automatycznie załadowane, zależy od Twojego kodu. Jeśli używaszCursorLoader
, jest ładowany automatycznie, ponieważ istnieje zarejestrowany obserwator danych.Po wywołaniu
viewpager.setAdapter(pageradapter)
adaptergetCount()
jest ciągle wywoływany w celu budowania fragmentów. Więc jeśli dane są ładowane,getCount()
może zwrócić 0, więc nie trzeba tworzyć fałszywych fragmentów, aby nie były wyświetlane żadne dane.Po załadowaniu danych adapter nie będzie budował fragmentów automatycznie, ponieważ
getCount()
wciąż ma wartość 0, więc możemy ustawić rzeczywiście załadowany numer danych, który ma zostać zwróconygetCount()
, a następnie wywołać numer adapteranotifyDataSetChanged()
.ViewPager
zacznij tworzyć fragmenty (tylko pierwsze 2 fragmenty) według danych w pamięci. Jest to zrobione przednotifyDataSetChanged()
zwrotem. NastępnieViewPager
ma odpowiednie fragmenty, których potrzebujesz.Jeśli dane w bazie danych i pamięci są zarówno aktualizowane (zapis), lub tylko dane w pamięci są aktualizowane (zapisywanie), lub aktualizowane są tylko dane w bazie danych. W dwóch ostatnich przypadkach, jeśli dane nie są automatycznie ładowane z bazy danych do pamięci (jak wspomniano powyżej).
ViewPager
I adapter pager właśnie do czynienia z danymi w pamięci.Więc kiedy dane w pamięci są aktualizowane, wystarczy wywołać adapter
notifyDataSetChanged()
. Ponieważ fragment jest już utworzony, adapteronItemPosition()
zostanie wywołany przednotifyDataSetChanged()
zwróceniem. Nic nie trzeba robićgetItemPosition()
. Następnie dane są aktualizowane.źródło
notifyDataSetChanged()
a następnie zaktualizować automatycznie, ponieważ fragment (z widokiem mapy), którego używam, odświeży się. jeśli nie jest, jak fragment statyczny, będę musiał zadzwonićonItemPositon()
iPOSITION_NONE
przepraszam za toWypróbuj
destroyDrawingCache()
ViewPager ponotifyDataSetChanged()
w swoim kodzie.źródło
Fragments
z pagera widokowego. Więc dziękuję!Po godzinach frustracji podczas próby wszystkich powyższych rozwiązań w celu przezwyciężenia tego problemu, a także próbują wiele rozwiązań na innych podobnych pytań, takich jak ten , ten i ten , który wszystko FAILED ze mną, aby rozwiązać ten problem i aby
ViewPager
zniszczyć staryFragment
i wypełnićpager
z nowyFragment
s. Rozwiązałem problem w następujący sposób:1) Ustaw
ViewPager
klasę na rozszerzeniaFragmentPagerAdapter
w następujący sposób:2) Utwórz element dla
ViewPager
tego skleputitle
ifragment
następujące elementy:3) Ustaw konstruktor
ViewPager
weź mojąFragmentManager
instancję, aby przechował ją wclass
następujący sposób:4) Utwórz metodę, aby ponownie ustawić
adapter
danych z nowych danych, usuwając wszystkie poprzedniefragment
zefragmentManager
sobą bezpośrednio, abyadapter
ustawić nowyfragment
z nową listą ponownie w następujący sposób:5) Z kontenera
Activity
lubFragment
nie inicjuj ponownie adaptera nowymi danymi. Ustaw nowe dane za pomocą metodysetPagerItems
z nowymi danymi w następujący sposób:Mam nadzieję, że to pomoże.
źródło
Z jakiegoś powodu żadna z odpowiedzi nie działała dla mnie, więc musiałem zastąpić metodę restoreState bez wywoływania super w moim fragmentStatePagerAdapter. Kod:
źródło
Lekko zmodyfikowałem rozwiązanie dostarczone przez Billa Phillipsa, aby dostosować je do moich potrzeb
aby
getItemPosition()
zwrotyPOSITION_NONE
tylko do tych fragmentów, które są obecnie wFragmentManager
przypadkugetItemPosition
nazywa. (Zauważ, że toFragmentStatePager
iViewPager
powiązane z nim są zawarte we fragmencie nie będącym działaniem)źródło
Miałem podobny problem, ale nie chcę ufać istniejącym rozwiązaniom (na stałe zakodowane nazwy znaczników itp.) I nie mogłem sprawić, by rozwiązanie M-WaJeEh działało dla mnie. Oto moje rozwiązanie:
Przechowuję odwołania do fragmentów utworzonych w getItem w tablicy. Działa to dobrze, dopóki aktywność nie zostanie zniszczona z powodu zmiany konfiguracji lub braku pamięci lub czegokolwiek (-> po powrocie do aktywności fragmenty wracają do ostatniego stanu bez ponownego wywołania „getItem”, a zatem bez aktualizacji tablicy ).
Aby uniknąć tego problemu, zaimplementowałem instantiateItem (ViewGroup, int) i zaktualizowałem tam moją tablicę, jak poniżej:
Tak więc z jednej strony cieszę się, że znalazłem rozwiązanie, które działa dla mnie i chciałem się z tobą podzielić, ale chciałem również zapytać, czy ktoś inny próbował czegoś podobnego i czy jest jakiś powód, dla którego nie powinienem był tego robić czy to tak? Jak dotąd działa dla mnie bardzo dobrze ...
źródło
myFragments
wpublic void destroyItem(ViewGroup container, int position, Object object)
jak dobrze więc nie chwycić nieświeży odniesienie fragement.Korzystam z biblioteki EventBus do aktualizacji
Fragment
treściViewPager
. Logika jest prosta, podobnie jak dokument EventBus, jak to zrobić . Nie ma potrzeby kontrolowaniaFragmentPagerAdapter
instancji. Kod jest tutaj:1: Zdefiniuj zdarzenia
Określ, który komunikat jest potrzebny do aktualizacji.
2. Przygotuj subskrybentów
Napisz poniższy kod we fragmencie, który wymaga aktualizacji.
3.Post wydarzenia
Napisz poniższy kod w innym
Activity
lub innym,Fragment
który musi zaktualizować parametrźródło
Jeśli chcesz korzystać z FragmentStatePagerAdapter, spójrz na https://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary% 20Stars & groupby = & sort = & id = 37990 . Występują problemy z FragmentStatePagerAdapter, które mogą, ale nie muszą, powodować kłopotu z twoim przypadkiem użycia.
Link ma również kilka rozwiązań. Niewiele może pasować do twoich wymagań.
źródło
Przeżyłem ten sam problem i szukałem zbyt wiele razy. Jakakolwiek odpowiedź podana w stackoverflow lub przez google nie była rozwiązaniem mojego problemu. Mój problem był łatwy. Mam listę, pokazuję ją w przeglądarce. Po dodaniu nowego elementu do nagłówka listy i odświeżeniu podglądu nic się nie zmieniło. Moje ostateczne rozwiązanie było bardzo łatwe dla każdego. Gdy nowy element zostanie dodany do listy i chcesz odświeżyć listę. Najpierw ustaw adapter podglądu na null, a następnie ponownie utwórz adapter i ustaw i dla niego na viewpager.
Upewnij się, że adapter musi rozszerzyć FragmentStatePagerAdapter
źródło
Oto moja implementacja, która zawiera informacje z @Bill Phillips One przez większość czasu jest buforowana fragmentami, z wyjątkiem sytuacji, gdy dane uległy zmianie. Prosty i wydaje się działać dobrze.
MyFragmentStatePagerAdapter.java
MyActivity.java
źródło
Próbowałem tylu różnych podejść, ale żadne z nich tak naprawdę nie rozwiało mojego problemu. Poniżej przedstawiam, w jaki sposób rozwiązuję to za pomocą kombinacji rozwiązań dostarczonych przez was wszystkich. Dziękuję wszystkim.
Chcę tylko odświeżyć stronę 0 po onResume ().
W mojej FragmentsMain znajduje się publiczna „strona” całkowita, która może mi powiedzieć, czy jest to strona, którą chcę odświeżyć.
źródło
Wiem, że spóźniłem się na przyjęcie. Rozwiązałem problem, dzwoniąc
TabLayout#setupWithViewPager(myViewPager);
zaraz poFragmentPagerAdapter#notifyDataSetChanged();
źródło
To rozwiązanie nie będzie działać dla wszystkich, ale w moim przypadku każdy fragment w moim ViewPager ma inną klasę i tylko jedna z nich istnieje na raz.
Przy takim ograniczeniu to rozwiązanie jest bezpieczne i powinno być bezpieczne do użycia w produkcji.
Jeśli masz wiele wersji tego samego fragmentu, możesz użyć tej samej strategii do wywołania metod na tych fragmentach, aby ustalić, czy jest to fragment, który chcesz zaktualizować.
źródło
Może to komuś pomóc - w moim przypadku przy wstawianiu nowej strony pager podglądu pytał dwukrotnie o pozycję istniejącego fragmentu, ale nie pytał o pozycję nowego elementu, powodując nieprawidłowe zachowanie i brak wyświetlania danych.
Skopiuj źródło dla FragmentStatePagerAdapter (wydaje się, że nie był aktualizowany od wieków).
Przesłoń powiadomienieDataSetChanged ()
Dodaj kontrolę poczytalności, aby destroyItem (), aby uniknąć awarii:
źródło
Przejrzałem wszystkie powyższe odpowiedzi i wiele innych postów, ale wciąż nie mogłem znaleźć czegoś, co zadziałałoby dla mnie (z różnymi typami fragmentów wraz z dynamicznym dodawaniem i usuwaniem zakładek). Poniższe podejście FWIW działało dla mnie (na wypadek, gdyby ktoś miał takie same problemy).
źródło
Użyj FragmentStatePagerAdapter zamiast FragmentPagerAdapter, jeśli chcesz odtworzyć lub ponownie załadować fragment na podstawie indeksu Na przykład, jeśli chcesz ponownie załadować fragment inny niż FirstFragment, możesz sprawdzić instancję i zwrócić pozycję w ten sposób
źródło
Musisz zmienić element mFragments getItemPosition w instantiateItem.
Oparty na AndroidX FragmentStatePagerAdapter.java, ponieważ
mFragments
pozycja elementów nie zmienia się podczas wywoływania powiadomieniaDataSetChanged ().Źródło: https://github.com/cuichanghao/infivt/blob/master/library/src/main/java/cc/cuichanghao/library/FragmentStatePagerChangeableAdapter.java
Przykład: https://github.com/cuichanghao/infivt/blob/master/app/src/main/java/cc/cuichanghao/infivt/MainActivityChangeablePager.kt
Możesz uruchomić ten projekt, aby potwierdzić sposób działania. https://github.com/cuichanghao/infivt
źródło