Grundlegendes zu setRetainInstance (boolean) von Fragment

341

Beginnend mit der Dokumentation:

public void setRetainInstance (boolesche Aufbewahrung)

Steuern Sie, ob eine Fragmentinstanz während der Neuerstellung der Aktivität beibehalten wird (z. B. aufgrund einer Konfigurationsänderung). Dies kann nur mit Fragmenten verwendet werden, die sich nicht im Backstack befinden. Wenn festgelegt, unterscheidet sich der Fragmentlebenszyklus geringfügig, wenn eine Aktivität neu erstellt wird:

  • onDestroy () wird nicht aufgerufen (onDetach () jedoch weiterhin, da das Fragment von seiner aktuellen Aktivität getrennt wird).
  • onCreate (Bundle) wird nicht aufgerufen, da das Fragment nicht neu erstellt wird.
  • onAttach (Aktivität) und onActivityCreated (Bundle) werden weiterhin aufgerufen.

Ich habe ein paar Fragen:

  • Behält das Fragment auch seine Ansicht bei oder wird dies bei Konfigurationsänderungen neu erstellt? Was genau bedeutet "beibehalten"?

  • Wird das Fragment zerstört, wenn der Benutzer die Aktivität verlässt?

  • Warum funktioniert es nicht mit Fragmenten auf dem Backstack?

  • In welchen Anwendungsfällen ist diese Methode sinnvoll?

Ixx
quelle
4
ähnliche Frage mit guten Informationen: Warum Fragment # setRetainInstance (boolean) verwenden?
Richard Le Mesurier

Antworten:

348

Schauen Sie sich zunächst meinen Beitrag zu aufbewahrten Fragmenten an. Es könnte helfen.

Um Ihre Fragen zu beantworten:

Behält das Fragment auch seinen Ansichtsstatus bei oder wird dies bei Konfigurationsänderungen neu erstellt - was genau wird "beibehalten"?

Ja, der FragmentStatus wird während der Konfigurationsänderung beibehalten. Insbesondere bedeutet "beibehalten", dass das Fragment bei Konfigurationsänderungen nicht zerstört wird. Das heißt, das Fragmentwird auch dann beibehalten , wenn die Konfigurationsänderung dazu führt, dass der Basiswert Activityzerstört wird.

Wird das Fragment zerstört, wenn der Benutzer die Aktivität verlässt?

Genau wie Activitys kann Fragments vom System zerstört werden, wenn die Speicherressourcen niedrig sind. Ob Ihre Fragmente ihren Instanzstatus über Konfigurationsänderungen hinweg beibehalten, hat keinen Einfluss darauf, ob das System das Fragments zerstört, sobald Sie das verlassen Activity. Wenn Sie das verlassen Activity(dh durch Drücken der Home-Taste), kann das Fragments zerstört werden oder nicht. Wenn Sie das Activitydurch Drücken der Zurück-Taste verlassen (wodurch das aufgerufen finish()und effektiv zerstört wird Activity), werden auch alle Activityangehängten Fragments zerstört.

Warum funktioniert es nicht mit Fragmenten auf dem Backstack?

Es gibt wahrscheinlich mehrere Gründe, warum es nicht unterstützt wird, aber der offensichtlichste Grund für mich ist, dass das Activityeinen Verweis auf das enthält FragmentManagerund das FragmentManagerden Backstack verwaltet. Das heißt, unabhängig davon, ob Sie Ihr Fragments behalten oder nicht, wird der Activity(und damit der FragmentManagerBackstack) bei einer Konfigurationsänderung zerstört. Ein weiterer Grund, warum es möglicherweise nicht funktioniert, ist, dass es schwierig werden könnte, wenn sowohl beibehaltene als auch nicht beibehaltene Fragmente auf demselben Backstack existieren dürfen.

In welchen Anwendungsfällen ist diese Methode sinnvoll?

Behaltene Fragmente können sehr nützlich sein, um Statusinformationen - insbesondere die Thread-Verwaltung - über Aktivitätsinstanzen zu verbreiten. Beispielsweise kann ein Fragment als Host für eine Instanz von Threadoder zur AsyncTaskVerwaltung seines Betriebs dienen. Weitere Informationen finden Sie in meinem Blogbeitrag zu diesem Thema.

Im Allgemeinen würde ich es ähnlich behandeln wie onConfigurationChangedmit einemActivity ... Verwenden Sie es nicht als Pflaster, nur weil Sie zu faul sind, um eine Orientierungsänderung korrekt zu implementieren / zu behandeln. Verwenden Sie es nur, wenn Sie es brauchen.

Alex Lockwood
quelle
37
Ansichtsobjekte werden nicht beibehalten, sondern bei Konfigurationsänderungen immer zerstört.
Markus Junginger
103
Soweit ich das beurteilen kann setRetainInstance(true), werden das FragmentJava-Objekt und sein gesamter Inhalt beim Drehen nicht zerstört, sondern die Ansicht wird neu erstellt. Das onCreatedView()heißt nochmal. Es ist im Grunde die Art und Weise, wie es Activitiesseit Android 1.0 hätte funktionieren sollen . Ich denke nicht, dass es "faul" ist, es zu benutzen, oder dass es nicht "richtig" ist. Tatsächlich kann ich nicht verstehen, warum dies nicht die Standardeinstellung ist oder warum Sie es jemals deaktivieren möchten.
Timmmm
24
Ich finde Ihre Erklärung für "Warum funktioniert es nicht mit Fragmenten auf dem Backstack?" schwierig zu verstehen. Aber vielleicht bin ich dumm :(
HGPB
13
@dierre Eine Aktivität kann auf viele Arten zerstört werden. Wenn Sie beispielsweise auf "Zurück" klicken, wird die Aktivität zerstört. Wenn Sie auf "Startseite" klicken, wird die Aktivität gestoppt und kann zu einem späteren Zeitpunkt zerstört werden, wenn der Arbeitsspeicher knapp wird. Beibehaltene Fragments werden nur bei Konfigurationsänderungen beibehalten, bei denen die zugrunde liegende Aktivität zerstört und sofort neu erstellt werden soll. In allen anderen Fällen, in denen die Aktivität zerstört wird, werden auch die zurückgehaltenen Fragmente zerstört.
Alex Lockwood
3
@AlexLockwood können Sie bitte Folgendes bestätigen: Auch wenn setRetainInstance(true)es verwendet wird, muss man immer noch seine eigene Persistenz ( savedInstanceStateoder auf andere Weise) implementieren , um alle Szenarien verarbeiten zu können: zB "Home-Schlüssel, drehen, zurück zur App" erstellt mein Fragment mit dem Konstruktor neu Aufruf, wobei alle Statusvariablen verloren gehen. Ich habe eine AsyncTaskVariable als Mitglied. Deshalb möchte ich sie beibehalten. Wenn sie funktionieren soll, muss ich die Aufgabe stoppen, den Status speichern und fortfahren, wenn der Benutzer zurückkommt. Alles in allem ist dies nur ein schneller Weg, um bei der Rotation zu helfen, aber ansonsten im Allgemeinen nutzlos.
TWiStErRob
28

setRetaininstanceist nur nützlich, wenn Ihre activityaufgrund einer Konfigurationsänderung zerstört und neu erstellt wird, da die Instanzen während eines Aufrufs von gespeichert werden onRetainNonConfigurationInstance. Das heißt, wenn Sie das Gerät drehen, bleiben die beibehaltenen Fragmente dort (sie werden nicht zerstört und neu erstellt). Wenn jedoch die Laufzeit die Aktivität zum Zurückfordern von Ressourcen beendet, bleibt nichts übrig. Wenn Sie die Zurück-Taste drücken und die Aktivität beenden, wird alles zerstört.

Normalerweise verwende ich diese Funktion, um die Orientierung zu ändern und die Zeit zu ändern. Ich habe eine Reihe von Bitmaps vom Server heruntergeladen und jede ist 1 MB groß. Wenn der Benutzer versehentlich sein Gerät dreht, möchte ich die gesamte Download-Arbeit auf keinen Fall erneut ausführen Ich erstelle ein FragmentHalten meiner Bitmaps und füge es dem Manager hinzu und rufe auf setRetainInstance. Alle Bitmaps sind noch vorhanden, auch wenn sich die Bildschirmausrichtung ändert.

Suitianshi
quelle
Erstellen Sie "Nur-Daten" -Fragmente (ohne Widget) nur als Halter für Ihre Bitmaps oder können diese Fragmente auch Widgets enthalten? Ich habe etwas über die Gefahr von Speicherlecks gelesen, wenn das Fragment etwas enthält, das mit Kontext / Aktivität zu
tun hat
Das Framework löscht die mActivityReferenz für Sie. Ich weiß aber nicht, ob die Laufzeit in diesem Fall auch Widgets in der Fragmentinstanz löschen würde. Bitte probieren Sie es aus oder tauchen Sie in den Quellcode ein.
Suitianshi
Schönes Beispiel dafür, wann wir die setRetaininstance
Mu Sa
12

Mit SetRetainInstance (true) kann das Fragment überleben. Seine Mitglieder bleiben bei Konfigurationsänderungen wie Rotation erhalten. Es kann jedoch trotzdem getötet werden, wenn die Aktivität im Hintergrund beendet wird. Wenn die enthaltende Aktivität im Hintergrund vom System beendet wird, sollte der Instanzstatus von dem System gespeichert werden, das Sie in SaveInstanceState ordnungsgemäß verarbeitet haben. Mit anderen Worten, der onSaveInstanceState wird immer aufgerufen. Obwohl onCreateView nicht aufgerufen wird, wenn SetRetainInstance true ist und Fragment / Aktivität noch nicht beendet ist, wird es dennoch aufgerufen, wenn es getötet wird und versucht wird, zurückgebracht zu werden.

Hier sind einige Analysen der Android-Aktivität / Fragment-Hoffnung, die es hilft. http://ideaventure.blogspot.com.au/2014/01/android-activityfragment-life-cycle.html

Kejun Xia
quelle
7
Ich sehe definitiv, dass onCreateView beim Drehen des Bildschirms erneut auf dem beibehaltenen Fragment aufgerufen wird.
aij
Ist dieser Link dein eigener Blog? Sie sollten dies klarstellen, wenn dies der Fall ist.
Flexo
4

setRetainInstance () - Veraltet

Als Fragmente Version 1.3.0-alpha01

Die Methode setRetainInstance () für Fragmente ist veraltet. Mit der Einführung von ViewModels verfügen Entwickler über eine spezielle API zum Beibehalten des Status, die Aktivitäten, Fragmenten und Navigationsdiagrammen zugeordnet werden kann. Auf diese Weise können Entwickler ein normales, nicht beibehaltenes Fragment verwenden und den spezifischen Status, den sie beibehalten möchten, getrennt halten, wodurch eine gemeinsame Quelle von Lecks vermieden wird, während die nützlichen Eigenschaften einer einzelnen Erstellung und Zerstörung des beibehaltenen Status (nämlich des Konstruktors des ViewModel) beibehalten werden und der empfangene onCleared () - Rückruf).

Gastón Saillén
quelle
2

setRetainInstance (boolean) ist nützlich, wenn Sie eine Komponente haben möchten, die nicht an den Aktivitätslebenszyklus gebunden ist. Diese Technik wird zum Beispiel von rxloader verwendet, um "den Aktivitätslebenszyklus von Android für rxjavas Observable zu handhaben" (den ich hier gefunden habe ).

Marian Paździoch
quelle