Was ist der Unterschied zwischen FragmentPagerAdapter und FragmentStatePagerAdapter?

375

Was ist der Unterschied zwischen FragmentPagerAdapterund FragmentStatePagerAdapter?

Über den FragmentPagerAdapterGoogle-Leitfaden heißt es:

Diese Version des Pagers eignet sich am besten für den Fall, dass eine Handvoll normalerweise statischerer Fragmente durchlaufen werden müssen, z. B. eine Reihe von Registerkarten. Das Fragment jeder Seite, die der Benutzer besucht, wird gespeichert, obwohl die Ansichtshierarchie möglicherweise zerstört wird, wenn sie nicht sichtbar ist. Dies kann dazu führen, dass eine erhebliche Menge an Speicher verwendet wird, da Fragmentinstanzen eine beliebige Menge an Zustand beibehalten können. Berücksichtigen Sie bei größeren Seitenmengen FragmentStatePagerAdapter.

Und über FragmentStatePagerAdapter:

Diese Version des Pagers ist nützlicher, wenn eine große Anzahl von Seiten vorhanden ist und eher wie eine Listenansicht funktioniert. Wenn Seiten für den Benutzer nicht sichtbar sind, wird möglicherweise das gesamte Fragment zerstört, wobei nur der gespeicherte Status dieses Fragments beibehalten wird. Dies ermöglicht es dem Pager, mit jeder besuchten Seite viel weniger Speicher zu belegen als FragmentPagerAdapterauf Kosten eines möglicherweise höheren Overheads beim Wechseln zwischen Seiten.

Ich habe also nur 3 Fragmente. Alle sind jedoch separate Module mit einer großen Datenmenge.

Fragment1behandelt einige Daten (die Benutzer eingeben) und übergibt sie über Aktivität an Fragment2, was nur eine einfache ist ListFragment. Fragment3ist auch ein ListFragment.

Meine Fragen sind also : Welchen Adapter soll ich verwenden? FragmentPagerAdapteroder FragmentStatePagerAdapter?

AlexMomotov
quelle
2
Ich denke, wenn Sie nur 3 Fragmente haben, können Sie FragmentPagerAdapter verwenden. Die Registerkarten für diese Fragmente werden wahrscheinlich alle gleichzeitig sichtbar sein.
IgorGanapolsky
2
Dieser Beitrag sparte meine 5-6 Stunden, weil ich einen falschen
Adaptertyp verwende
1
Die Antwort auf diese Frage wirft eine weitere Frage auf stackoverflow.com/questions/9156406/…
Piyush Kukadiya
gibt es FragmentPagerAdapterund FragmentStatePagerAdapteraber was ist FragmentStateAdapter?
the_prole

Antworten:

292

Wie die Dokumente sagen, denken Sie so darüber nach. Wenn Sie eine Anwendung wie einen Buchleser ausführen, möchten Sie nicht alle Fragmente gleichzeitig in den Speicher laden. Sie möchten laden und zerstören, Fragmentswährend der Benutzer liest. In diesem Fall werden Sie verwenden FragmentStatePagerAdapter. Wenn Sie nur 3 "Registerkarten" anzeigen, die nicht viele schwere Daten (wie Bitmaps) enthalten, ist dies FragmentPagerAdaptermöglicherweise gut für Sie geeignet. Beachten Sie außerdem, dass ViewPagerstandardmäßig 3 Fragmente in den Speicher geladen werden. Der erste, den AdapterSie erwähnen, kann die ViewHierarchie zerstören und bei Bedarf neu laden, der zweite Adapterspeichert nur den Status von Fragmentund zerstört ihn vollständig. Wenn der Benutzer dann zu dieser Seite zurückkehrt, wird der Status abgerufen.

Emmanuel
quelle
Ich habe mehrere Schaltflächen und Textansichten in Fragment1 und ListView, die Elemente dynamisch in Fragment2 und Fragment3 generieren. Halten Sie es für eine gute Idee, FragmentStatePagerAdapter zu verwenden und alle Daten in Activity zu speichern und sie über Bundle an Fragmente zu übergeben?
AlexMomotov
2
@AlexMomotov Ansichten im Layout des Fragments haben nichts mit der Auswahl von FragmentStatePagerAdapter zu tun. Die Frage hier ist die Anzahl der Fragmente, die durchlaufen werden.
IgorGanapolsky
1
Grundsätzlich gibt es nichts dafür FragmentPagerAdapter, es zu benutzen.
Tomasz Mularczyk
3
@Tomasz hat den Vorteil, FragmentPagerAdapterdass das Wechseln zwischen Fragmenten viel schneller sein kann, da die tatsächlichen FragmentObjekte nicht jedes Mal neu erstellt werden müssen. Andererseits würde dies dazu führen, dass mehr Speicher benötigt wird, der die Fragmentobjekte im Speicher hält.
Richard Le Mesurier
Ich habe 3 Registerkarten / Seiten (die jeweils eine WebView anzeigen), habe also FragmentPagerAdapter verwendet . Die letzte Seite wird jedoch immer noch neu gezeichnet, wenn ich von der ersten Seite dorthin wische. Um dies zu lösen, habe ich verwendet viewPager.setOffscreenPageLimit(2).
Ban-Geoengineering
131
  • FragmentPagerAdapterspeichert das gesamte Fragment im Speicher und kann den Speicheraufwand erhöhen, wenn eine große Anzahl von Fragmenten in verwendet wird ViewPager.

  • Im Gegensatz zu seinem Geschwister FragmentStatePagerAdapterspeichert es nur den gespeicherten Instanzstatus von Fragmenten und zerstört alle Fragmente, wenn sie den Fokus verlieren.

  • Daher FragmentStatePagerAdaptersollte verwendet werden, wenn dynamische Fragmente wie Fragmente mit Widgets verwendet werden müssen, da deren Daten in der savedInstanceStateDatei gespeichert werden können. Dies wirkt sich auch dann nicht auf die Leistung aus, wenn eine große Anzahl von Fragmenten vorhanden ist.

  • Im Gegensatz dazu sollte sein Geschwister FragmentPagerAdapterverwendet werden, wenn wir das gesamte Fragment im Speicher speichern müssen.

  • Wenn ich sage, dass das gesamte Fragment im Speicher bleibt, bedeutet dies, dass seine Instanzen nicht zerstört werden und einen Speicheraufwand verursachen würden. Daher wird empfohlen, FragmentPagerAdapternur zu verwenden , wenn eine geringe Anzahl von Fragmenten für vorhanden ist ViewPager.

  • Es wäre sogar noch besser, wenn die Fragmente statisch wären, da sie keine große Anzahl von Objekten enthalten würden, deren Instanzen gespeichert würden.

Um genauer zu sein,

FragmentStatePagerAdapter:

  • Mit FragmentStatePagerAdapterwird Ihr nicht benötigtes Fragment zerstört. Eine Transaktion wird festgeschrieben, um das Fragment vollständig aus Ihren Aktivitäten zu entfernen FragmentManager.

  • Der Status in FragmentStatePagerAdapterergibt sich aus der Tatsache, dass die Fragmente Bundleab dem savedInstanceStateZeitpunkt der Zerstörung gespeichert werden. Wenn der Benutzer zurück navigiert, wird das neue Fragment unter Verwendung des Status des Fragments wiederhergestellt.

FragmentPagerAdapter:

  • Im Vergleich FragmentPagerAdaptermacht nichts dergleichen. Wenn das Fragment nicht mehr benötigt wird. FragmentPagerAdapterruft detach(Fragment)die Transaktion statt remove(Fragment).

  • Dadurch wird die Ansicht des Fragments zerstört, die Instanz FragmentManagerdes Fragments bleibt jedoch in der .iv. Die in der erstellten Fragmente FragmentPagerAdapterwerden also niemals zerstört.

Steve
quelle
2
Warum hast du 2 Antworten?
Jared Burrows
Was bringt es, ganze Fragmente im Gedächtnis zu behalten?
Tomasz Mularczyk
4
@Tomek: Wenn das nächste Fragment bereits instanziiert ist (z. B. FragmentPagerAdapter), kann es beim Wischen gerendert werden, sodass die Wischanimation flüssiger wird. Bei FragmentStatePagerAdapter ist die nächste Fragmentinstanz möglicherweise erst vorhanden, wenn Sie darüber streichen. Wenn die Erstellung eines großen Fragments teuer ist, wird in der Animation möglicherweise ein Ruckeln angezeigt. Es ist eine Frage der Leistung im Vergleich zum Speicherverbrauch.
Dalbergia
1
@ Jared Burrows bcoz einer ist nur AnswerText, der für kleine und statische Antworten gut ist, und der andere ist AnswerStateText, der für größere und dynamische Antworten ist
Simple Fellow
48

Hier ist ein Protokolllebenszyklus jedes Fragments, in ViewPagerdem 4 Fragmente und enthalten sindoffscreenPageLimit = 1 (default value)

FragmentStatePagerAdapter

Gehe zu Fragment1 (Aktivität starten)

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

Gehe zu Fragment2

Fragment3: onCreateView
Fragment3: onStart

Gehe zu Fragment3

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

Gehe zu Fragment4

Fragment2: onStop
Fragment2: onDestroyView
Fragment2: onDestroy

FragmentPagerAdapter

Gehe zu Fragment1 (Aktivität starten)

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

Gehe zu Fragment2

Fragment3: onCreateView
Fragment3: onStart

Gehe zu Fragment3

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

Gehe zu Fragment4

Fragment2: onStop
Fragment2: onDestroyView

Fazit : FragmentStatePagerAdapterRufen Sie an, onDestroywenn das Fragment überwunden ist, ohne dies zu offscreenPageLimittun FragmentPagerAdapter.

Hinweis : Ich denke, wir sollten FragmentStatePagerAdapterfür eine ViewPagerSeite mit viel Seite verwenden, da dies für die Leistung gut ist.

Beispiel für offscreenPageLimit:

Wenn wir zu Fragment3 gehen, wird Fragment1 (oder Fragment5, falls vorhanden) zerstört, weil offscreenPageLimit = 1. Wenn wir einstellen offscreenPageLimit > 1, wird es nicht zerstören.
Wenn wir in diesem Beispiel festlegen offscreenPageLimit=4, gibt es keinen Unterschied zwischen der Verwendung FragmentStatePagerAdapteroder FragmentPagerAdapterweil Fragment niemals aufruft onDestroyViewund onDestroywenn wir die Registerkarte wechseln

Github Demo hier

Phan Van Linh
quelle
So ein toller Abschluss!
Rahul Rastogi
nette Erklärung
Gourav Singhal
1
Schöne Erklärung. Sie sagten, dass die Verwendung von FragmentStatePagerAdapter bei vielen Seiten gut für die Leistung ist. Meinten Sie, dass es gut zum Speichern von Speicher ist? Das Ziel, so wie ich es verstehe, ist es, Speicher für den Fall möglicher vieler Fragmentinstanzen zu erhalten - Leistung ist also der implizite Vorteil; Das explizite Ziel ist es, die Erinnerung zu bewahren
Hatzil
38

In der Dokumentation oder in den Antworten auf dieser Seite wird nicht ausdrücklich darauf hingewiesen (obwohl dies von @Naruto impliziert wird), dass FragmentPagerAdapterdie Fragmente nicht aktualisiert werden, wenn sich die Daten im Fragment ändern, da das Fragment im Speicher bleibt.

Selbst wenn Sie nur eine begrenzte Anzahl von Fragmenten anzeigen möchten, müssen Sie FragmentStatePagerAdapter verwenden, wenn Sie Ihre Fragmente aktualisieren möchten (z. B. wenn Sie die Abfrage erneut ausführen, um die listView im Fragment zu aktualisieren).

Mein ganzer Punkt hier ist, dass die Anzahl der Fragmente und ob sie ähnlich sind oder nicht, nicht immer der Schlüsselaspekt ist, der berücksichtigt werden muss. Ob Ihre Fragmente dynamisch sind oder nicht, ist ebenfalls entscheidend.

JDenais
quelle
Angenommen, ich habe 2 Fragmente, 1 Recycling-Ansicht in Fragment A. Wenn ich auf ein Element klicke, ändert sich der Inhalt von Fragment B. Angenommen, ich mache fragB.setText ("blablabla"). Ich sollte den Staat pagerthen verwenden?
Ced
Nicht sicher, aber ich würde ja sagen. Probieren Sie einfach beide aus, es ist wirklich einfach und schnell, Ihren Code von einem zum anderen zu ändern.
JDenais
@ JDenais Bist du sicher, dass das richtig ist? Ich verwende FragmentPagerAdapterin meiner Aktivität einen ViewPager, um zwei Fragmente anzuzeigen - wobei jedes Fragment eine Liste enthält. Meine erste Liste heißt "Alle Berichte" und die zweite Liste ist "Lieblingsberichte". Wenn ich in der ersten Liste auf das Sternsymbol für einen Bericht tippe, wird die Datenbank aktualisiert, um den Favoritenstatus dieses Berichts umzuschalten. Ich wische dann über und sehe diesen Bericht erfolgreich in der Benutzeroberfläche der zweiten Liste. Vielleicht werden die Instanzen im Speicher behalten, aber in einigen Fällen (z. B. in meinen) wird der Inhalt für FragmentPagerAdapter
Ban-Geoengineering
14

FragmentPagerAdapterspeichert die vorherigen Daten, die vom Adapter abgerufen werden, während FragmentStatePagerAdapterder neue Wert bei jeder Ausführung vom Adapter übernommen wird.

Vinay Kumar
quelle
4

FragmentStatePagerAdapter = Zum Aufnehmen einer großen Anzahl von Fragmenten in ViewPager. Da dieser Adapter das Fragment zerstört, wenn es für den Benutzer nicht sichtbar ist und nur savedInstanceState des Fragments zur weiteren Verwendung aufbewahrt wird. Auf diese Weise wird eine geringe Speichermenge verwendet und bei dynamischen Fragmenten eine bessere Leistung erzielt.

Dwivedi Ji
quelle
1

FragmentPagerAdapter : Das Fragment jeder Seite, die der Benutzer besucht, wird im Speicher gespeichert, obwohl die Ansicht zerstört wird. Wenn die Seite wieder sichtbar ist, wird die Ansicht neu erstellt, die Fragmentinstanz jedoch nicht neu. Dies kann dazu führen, dass eine erhebliche Menge an Speicher verwendet wird. FragmentPagerAdapter sollte verwendet werden, wenn das gesamte Fragment im Speicher gespeichert werden muss. FragmentPagerAdapter ruft bei der Transaktion "trennen" (Fragment) auf, anstatt "entfernen" (Fragment).

FragmentStatePagerAdapter : Die Fragmentinstanz wird zerstört, wenn sie für den Benutzer nicht sichtbar ist, mit Ausnahme des gespeicherten Status des Fragments. Dies führt dazu, dass nur wenig Speicher benötigt wird, und kann für die Verarbeitung größerer Datenmengen hilfreich sein. Sollte verwendet werden, wenn dynamische Fragmente wie Fragmente mit Widgets verwendet werden müssen, da deren Daten im savedInstanceState gespeichert werden könnten. Dies wirkt sich auch dann nicht auf die Leistung aus, wenn eine große Anzahl von Fragmenten vorhanden ist.

foroogh.Varmazyar
quelle