Jaka jest różnica między FragmentPagerAdapter i FragmentStatePagerAdapter?

374

Jaka jest różnica między FragmentPagerAdapteri FragmentStatePagerAdapter?

O FragmentPagerAdapterprzewodniku Google mówi:

Ta wersja pagera jest najlepsza do użycia, gdy istnieje garść zwykle bardziej statycznych fragmentów, które należy przełożyć, takich jak zestaw zakładek. Fragment każdej strony odwiedzanej przez użytkownika będzie przechowywany w pamięci, chociaż jej hierarchia widoków może zostać zniszczona, gdy nie będzie widoczna. Może to spowodować użycie znacznej ilości pamięci, ponieważ instancje fragmentów mogą utrzymać dowolną liczbę stanów. W przypadku większych zestawów stron należy rozważyć FragmentStatePagerAdapter.

Oraz o FragmentStatePagerAdapter:

Ta wersja pagera jest bardziej przydatna, gdy istnieje duża liczba stron, które działają bardziej jak widok listy. Gdy strony nie są widoczne dla użytkownika, cały ich fragment może zostać zniszczony, zachowując jedynie zapisany stan tego fragmentu. Dzięki temu pager może zatrzymać znacznie mniej pamięci związanej z każdą odwiedzaną stroną w porównaniu FragmentPagerAdapterz kosztem potencjalnie większego obciążenia przy przełączaniu między stronami.

Mam więc tylko 3 fragmenty. Ale wszystkie z nich są osobnymi modułami z dużą ilością danych.

Fragment1obsługuje niektóre dane (które wprowadzają użytkownicy) i przekazuje je poprzez aktywność do Fragment2, co jest po prostu proste ListFragment. Fragment3jest również ListFragment.

Więc moje pytania brzmią : Którego adaptera powinienem użyć? FragmentPagerAdapterczy FragmentStatePagerAdapter?

AlexMomotov
źródło
2
Myślę, że posiadanie tylko 3 fragmentów kwalifikuje cię do korzystania z FragmentPagerAdapter. Zakładki dla tych fragmentów będą prawdopodobnie wszystkie jednocześnie widoczne.
IgorGanapolsky
2
ten post oszczędził mi 5-6 godzin, ponieważ używam niewłaściwego typu adaptera
Nantaphop,
1
Odpowiedź na to pytanie rzuca jeszcze jedno pytanie stackoverflow.com/questions/9156406/…
Piyush Kukadiya
jest FragmentPagerAdapteri FragmentStatePagerAdapterco jest FragmentStateAdapter?
the_prole

Odpowiedzi:

291

Jak mówią doktorzy, pomyśl o tym w ten sposób. Jeśli miałbyś zrobić aplikację taką jak czytnik książek, nie będziesz chciał ładować wszystkich fragmentów na raz. Chcesz ładować i niszczyć, Fragmentsgdy użytkownik czyta. W takim przypadku użyjesz FragmentStatePagerAdapter. Jeśli po prostu wyświetlasz 3 „zakładki”, które nie zawierają dużej ilości ciężkich danych (np. Bitmaps), FragmentPagerAdapterMoże Ci się to dobrze przydać. Należy również pamiętać, że ViewPagerdomyślnie ładuje 3 fragmenty do pamięci. Pierwsze Adapter, o którym wspominasz, może zniszczyć Viewhierarchię i ponownie załadować ją w razie potrzeby, drugie Adaptertylko zapisuje stan Fragmenti całkowicie niszczy, jeśli użytkownik wróci do tej strony, stan zostanie przywrócony.

Emmanuel
źródło
Mam wiele Buttons i TextViews we Fragment1 i ListView, które generują elementy dynamicznie we Fragment2 i Fragment3. Czy uważasz, że warto używać FragmentStatePagerAdapter i przechowywać wszystkie dane w Activity, przekazując je do Fragmentów za pośrednictwem pakietu?
AlexMomotov
2
@AlexMomotov Widoki w układzie fragmentu nie mają nic wspólnego z wyborem FragmentStatePagerAdapter. Pytanie brzmi: ilość Fragmentów, przez które będzie stronicowana.
IgorGanapolsky
1
Zasadniczo więc nie ma nic na korzyść FragmentPagerAdapterkorzystania z niego.
Tomasz Mularczyk
3
@Tomasz ma tę zaletę, FragmentPagerAdapterże przełączanie między fragmentami może być znacznie szybsze, ponieważ rzeczywiste Fragmentobiekty nie muszą być przebudowywane za każdym razem. Z drugiej strony skończyłoby się to użyciem większej ilości pamięci, która utrzymywałaby fragmenty obiektów w pamięci.
Richard Le Mesurier
Mam 3 karty / strony (z których każda pokazuje WebView), więc użyłem FragmentPagerAdapter . Jednak ostatnia strona nadal jest przerysowywana, gdy przesuwam do niej od pierwszej strony. Aby to rozwiązać, użyłem viewPager.setOffscreenPageLimit(2).
zakaz geoinżynierii
131
  • FragmentPagerAdapterprzechowuje cały fragment w pamięci i może zwiększyć obciążenie pamięci, jeśli zostanie użyta duża liczba fragmentów ViewPager.

  • W przeciwieństwie do jego rodzeństwa, FragmentStatePagerAdapterprzechowuje tylko zapisaną częśćInstanceState fragmentów i niszczy wszystkie fragmenty, gdy stracą ostrość.

  • Dlatego FragmentStatePagerAdapternależy go stosować, gdy musimy używać fragmentów dynamicznych, takich jak fragmenty z widżetami, ponieważ ich dane mogą być przechowywane w. savedInstanceStateNie wpłynie to również na wydajność, nawet jeśli istnieje duża liczba fragmentów.

  • Przeciwnie, FragmentPagerAdapternależy użyć jego rodzeństwa, gdy musimy zapisać cały fragment w pamięci.

  • Kiedy mówię, że cały fragment jest przechowywany w pamięci, oznacza to, że jego instancje nie zostaną zniszczone i utworzą narzut pamięci. Dlatego zaleca się stosowanie FragmentPagerAdaptertylko w przypadku małej liczby fragmentów ViewPager.

  • Byłoby jeszcze lepiej, gdyby fragmenty były statyczne, ponieważ nie miałyby dużej liczby obiektów, których instancje byłyby przechowywane.

Aby być bardziej szczegółowym,

FragmentStatePagerAdapter:

  • z FragmentStatePagerAdapter, Twój niepotrzebny fragment zostanie zniszczony. Transakcja jest zobowiązana do całkowitego usunięcia fragmentu z Twojej aktywności FragmentManager.

  • Stan FragmentStatePagerAdapterpochodzi z faktu, że ocali fragment twojego fragmentu Bundleprzed savedInstanceStatezniszczeniem. Gdy użytkownik przejdzie wstecz, nowy fragment zostanie przywrócony przy użyciu stanu fragmentu.

FragmentPagerAdapter:

  • Przez porównanie FragmentPagerAdapternie robi nic takiego, gdy fragment nie jest już potrzebny. FragmentPagerAdapterwywołuje detach(Fragment)transakcję zamiast remove(Fragment).

  • To zniszczenie jest widokiem fragmentu, ale pozostawia instancję fragmentu żywą w. FragmentManagerWięc fragmenty utworzone w FragmentPagerAdapternie są nigdy niszczone.

Steve
źródło
2
Dlaczego masz 2 odpowiedzi?
Jared Burrows
jaka jest korzyść z zachowania całych fragmentów w pamięci?
Tomasz Mularczyk
4
@ Tomek: jeśli następny fragment jest już utworzony (np. FragmentPagerAdapter), będzie gotowy do renderowania po przesunięciu do niego, więc animacja przeciągnięcia będzie płynniejsza. W przypadku FragmentStatePagerAdapter kolejna instancja fragmentu może nie istnieć, dopóki nie przesuniesz do niej, a jeśli jest to duży fragment, którego utworzenie jest kosztowne, możesz zobaczyć zacinanie się animacji. Jest to kwestia wydajności vs. zużycia pamięci.
Dalbergia
1
@Jared Burrows bcoz jeden jest po prostu AnswerText, który jest dobry dla małych i statycznych odpowiedzi, a drugi to AnswerStateText, który jest dla większych i dynamicznych odpowiedzi
Simple Fellow
48

Oto cykl życia dziennika każdego fragmentu, w ViewPagerktórym znajdują się 4 fragmenty ioffscreenPageLimit = 1 (default value)

FragmentStatePagerAdapter

Idź do Fragment1 (uruchomienie działania)

Fragment1: onCreateView
Fragment1: onStart
Fragment2: onCreateView
Fragment2: onStart

Idź do Fragment2

Fragment3: onCreateView
Fragment3: onStart

Idź do Fragment 3

Fragment1: onStop
Fragment1: onDestroyView
Fragment1: onDestroy
Fragment1: onDetach
Fragment4: onCreateView
Fragment4: onStart

Idź do Fragment 4

Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy

FragmentPagerAdapter

Idź do Fragment1 (uruchomienie działania)

Fragment1: onCreateView
Fragment1: onStart
Fragment2: onCreateView
Fragment2: onStart

Idź do Fragment2

Fragment3: onCreateView
Fragment3: onStart

Idź do Fragment 3

Fragment1: onStop
Fragment1: onDestroyView
Fragment4: onCreateView
Fragment4: onStart

Idź do Fragment 4

Fragment2: onStop
Fragment2: onDestroyView

Wniosek : FragmentStatePagerAdapterzadzwoń, onDestroygdy Fragment zostanie pokonany, offscreenPageLimita FragmentPagerAdapternie.

Uwaga : Myślę, że powinniśmy używać FragmentStatePagerAdaptertej, ViewPagerktóra ma dużo stron, ponieważ będzie to dobre dla wydajności.

Przykład stanowi offscreenPageLimit:

Jeśli idziemy do Fragment3, to będzie detroy Fragment1 (lub Fragment5 jeśli mają), ponieważ offscreenPageLimit = 1. Jeśli ustawimy offscreenPageLimit > 1, nie zniszczy.
Jeśli w tym przykładzie ustawimy offscreenPageLimit=4, nie ma różnicy między używaniem FragmentStatePagerAdapterlub FragmentPagerAdapterponieważ Fragment nigdy nie wywołuje onDestroyViewi onDestroykiedy zmieniamy tabulację

Demo Github tutaj

Phan Van Linh
źródło
Taki świetny sposób na zakończenie!
Rahul Rastogi
ładne wyjaśnienie
gourav singhal
1
Ładne wyjaśnienie. Powiedziałeś, że użycie FragmentStatePagerAdapter przy dużej liczbie stron jest dobre dla wydajności. Czy miałeś na myśli, że jest to dobre dla oszczędzania pamięci? Rozumiem, że celem jest zachowanie pamięci w przypadku wielu możliwych fragmentów Fragmentów - więc wydajność jest domyślną korzyścią; wyraźnym celem jest zachowanie pamięci
Hatzil
38

Coś, co nie zostało wyraźnie powiedziane w dokumentacji lub w odpowiedziach na tej stronie (nawet sugerowanej przez @Naruto), jest to, że FragmentPagerAdapternie zaktualizuje Fragmentów, jeśli dane w Fragmentie zmienią się, ponieważ zachowuje Fragment w pamięci.

Więc nawet jeśli masz ograniczoną liczbę fragmentów do wyświetlenia, jeśli chcesz móc odświeżyć swoje fragmenty (np. Ponownie uruchom zapytanie w celu zaktualizowania listView w fragmencie), musisz użyć FragmentStatePagerAdapter.

Chodzi mi o to, że liczba Fragmentów i to, czy są one podobne, nie zawsze jest kluczowym aspektem do rozważenia. Kluczowe jest także to, czy Twoje fragmenty są dynamiczne.

JDenais
źródło
Powiedzmy, że mam 2 fragmenty, 1 recyklingview w fragmencie A, kiedy klikam element, zmienia on zawartość fragmentu B, powiedzmy, że wykonuję fragB.setText („blablabla”). Czy powinienem użyć strony stanu?
Ced
Nie jestem pewien, ale powiedziałbym tak. Po prostu wypróbuj jedno i drugie, i tak naprawdę bardzo łatwo i szybko zmienisz kod z jednego na drugi.
JDenais,
@JDenais Czy na pewno to prawda? Używam FragmentPagerAdapterw mojej działalności, która korzysta z ViewPager, aby pokazać dwa fragmenty - gdzie każdy fragment zawiera listę. Moja pierwsza lista to „Wszystkie raporty”, a druga lista to „Ulubione raporty”. Na pierwszej liście, jeśli stuknę ikonę gwiazdki dla raportu, aktualizuje on bazę danych, aby przełączać ulubiony status tego raportu. Następnie przesuwam palcem po ekranie i z powodzeniem widzę ten raport w interfejsie użytkownika drugiej listy. Może więc instancje są przechowywane w pamięci, ale w niektórych przypadkach (np. Moje) zawartość faktycznie zaktualizuje się dobrze dla FragmentPagerAdapter
zakaz geoinżynierii
14

FragmentPagerAdapterprzechowuje poprzednie dane, które są pobierane z adaptera, a przy każdym FragmentStatePagerAdapteruruchomieniu pobiera nową wartość z adaptera.

vinay kumar
źródło
4

FragmentStatePagerAdapter = Aby pomieścić dużą liczbę fragmentów w ViewPager. Ponieważ ten adapter niszczy fragment, gdy nie jest on widoczny dla użytkownika i tylko zapisany parametrInstanceState fragmentu jest przechowywany do dalszego wykorzystania. W ten sposób wykorzystywana jest niewielka ilość pamięci i lepsza wydajność w przypadku fragmentów dynamicznych.

Dwivedi Ji
źródło
1

FragmentPagerAdapter : fragment każdej strony odwiedzanej przez użytkownika zostanie zapisany w pamięci, chociaż widok zostanie zniszczony. Kiedy strona będzie ponownie widoczna, widok zostanie odtworzony, ale instancja fragmentu nie zostanie odtworzona. Może to spowodować znaczne zużycie pamięci. FragmentPagerAdapter powinien być używany, gdy potrzebujemy przechowywać cały fragment w pamięci. Wywołania FragmentPagerAdapter odłączają (Fragment) w transakcji zamiast usuwać (Fragment).

FragmentStatePagerAdapter : instancja fragmentu jest niszczona, gdy nie jest widoczna dla użytkownika, z wyjątkiem stanu zapisanego fragmentu. Powoduje to użycie niewielkiej ilości pamięci i może być przydatne do obsługi większych zestawów danych. Powinien być stosowany, gdy musimy korzystać z fragmentów dynamicznych, takich jak fragmenty z widżetami, ponieważ ich dane mogą być przechowywane w saveInstanceState. Nie wpłynie to również na wydajność, nawet jeśli jest ich dużo.

foroogh.Varmazyar
źródło