Update: Es stellt sich heraus, dass das Problem von anderswo ist. Danke @Luksprog für das Aufzeigen, was ich übersehen habe.
NavigationDrawerFragment
implementiert. onCreate()
von NavigationDrawerFragment
aufgerufen, wobei das zuletzt ausgewählte Element beibehalten wird. NavigationDrawerFragment
selectItem () erneut auf, was meinen ausgewählten Menü-Handler auslöst. Dies verursacht das von Android wiederhergestellte ListFragment. Dies kann verhindert werden, indem Sie den aktiven Menüeintrag in meinem Menüauswahl-Handler-Code überprüfen.
Ich möchte den letzten Anzeigeseitenindex von ViewPager
beibehalten, wenn die Aktivität aus irgendeinem Grund neu erstellt wird, z. Orientierungsänderung.
Das ViewPager
ist in einem Fragment
(genannt ListFragment
), das an eine Aktivität angehängt ist. Ich verwende die compat-Bibliothek, also ist das Fragment eine Unterklasse von android.support.v4.app.Fragment
.
Ich dachte, dass dies durch Überschreiben der Methode onSaveInstanceState()
und Hinzufügen der entsprechenden Logik in onCreate()
geschehen könnte, wie in doc :
Um einen Neustart richtig zu handhaben, ist es wichtig, dass Sie Ihre Aktivität ausführen stellt seinen vorherigen Status über den normalen Aktivitätslebenszyklus wieder her welches Android onSaveInstanceState () aufruft, bevor es dein zerstört Aktivität, damit Sie Daten über den Anwendungsstatus speichern können. Sie kann dann den Zustand während onCreate () oder wiederherstellen onRestoreInstanceState ().
Aber die Situation scheint für Fragmente anders zu sein. Der Seitenindex kann korrekt wiederhergestellt werden, wenn ich von dieser ListFragment
zu einer anderen Aktivität navigiere und "zurück" drücke. Wenn ich jedoch mein Gerät rotiere, ist der Seitenindex verloren.
Ich habe etwas Protokollierung hinzugefügt, um zu sehen, was falsch ist. Aus dem Protokoll habe ich herausgefunden, dass, obwohl onSaveInstanceState()
von ListFragment
(ich nenne es ListFragment A) korrekt aufgerufen wird, diese bestimmte Fragment-Klasse nicht mehr in der Aktivität angezeigt wird. Wenn sich die Ausrichtung ändert und die Aktivität neu erstellt wird, ruft Android onSaveInstanceState()
gefolgt von onDetach()
auf, um dieses Fragment zu lösen. Dann erstellt Android eine neue Instanz von ListFragment
(ich nenne es ListFragment B) und hängt es an die neue, rotierte Aktivität an. Dieses ListFragment B hat ein leeres savedInstanceState
an den Konstruktor übergeben, und somit ist der letzte Seitenindex (und jede Konfiguration in savedInstanceState von Fragment A) verloren.
Tatsächlich wird eine neue Instanz von ListFragment
jedes Mal erstellt, wenn ein Bildschirm rotiert, aber es scheint, dass die alten nicht zerstört werden. Ich sehe Protokolle wie unten, wenn ich das Gerät rotiere:
Dies ist das Protokoll, nachdem ich den Bildschirm etwa 10 Mal gedreht habe. Die Nummer im Tag ist die Klasse hashCode()
. Die oberen Zeilen zeigen, dass onSaveInstanceState()
und onCreate()
der zuvor erstellten Fragmente immer noch aufgerufen werden, nachdem sie durch die letzte (1111031048) ersetzt wurden.
Beachten Sie, dass nicht setRetainInstance()
in der Fragmentklasse aufgerufen hat. Tatsächlich probierte ich sowohl setRetainInstance(false)
als auch setRetainInstance(true)
, aber es ändert nichts.
Habe ich hier etwas falsch gemacht? Ich kann verstehen, dass ListFragment
neu erstellt werden muss, aber warum savedInstanceState
ist null? Und wenn dies das erwartete Verhalten ist, was ist der richtige Weg, um meinen Bedarf zu lösen, d.h. den Seitenindex beizubehalten, wenn sich die Konfiguration ändert?
Es sollte möglich sein, den Seitenindex zu einer statischen Klassenvariablen zu machen, aber ich bin mir nicht sicher, ob es das Problem tatsächlich löst oder nur versteckt (weil ich Speicherleck im obigen Protokoll rieche).
Wie in der Frage aktualisiert, ist dies gelöst und nochmals danke an @Luksprog für das Aufzeigen, was ich übersehen habe.
Das Verhalten von Fragment
stimmt tatsächlich mit Activity
-Klassen überein.
Hier ist die Ursache meines Problems:
NavigationDrawerFragment
implementiert. onCreate()
von NavigationDrawerFragment
aufgerufen, wobei das zuletzt ausgewählte Element beibehalten wird. NavigationDrawerFragment
selectItem()
erneut auf, was meinen ausgewählten Handler für den Menüpunkt auslöst. Dies bewirkt, dass ListFragment
ersetzt wird. Dies kann verhindert werden, indem Sie den aktiven Menüeintrag in meinem Menüauswahl-Handler-Code überprüfen oder indem Sie den selectItem()
-Aufruf deaktivieren.
Auch wenn die Antwort bereits akzeptiert wurde, lassen Sie mich das noch genauer erläutern: Das "Problem" befindet sich in der Android Studio-Vorlage. Das Problem, auf das Edmund hingewiesen hat, ist das Navigieren in der Navigationsleiste, das das Menü aufruft, wenn es neu erstellt wird, wodurch das Fragment erneut aufgerufen wird. Um dies zu beheben, habe ich diese geringfügige Änderung an der von Android Studio vorgeschlagenen NavigationDrawerFragment.java-Datei vorgenommen. Original:
%Vor%Neu:
%Vor%Habe gerade einen halben Produktionstag verloren, um das herauszufinden. Ich hoffe, es kann jemand anderem helfen.
Verwenden Sie onCreateView()
anstelle von onCreate()
, was für Fragmente spezifisch ist und einen Unterschied machen kann.
Überschreibe onSaveInstanceState()
, um deinen Status zu speichern und stelle ihn in onCreateView()
mit savedInstanceState.get*()
wieder her. So machen wir es in unseren Apps, und es sollte funktionieren. Wie @Ari erwähnt, stelle sicher, dass super.onSaveInstanceState(outState)
aufgerufen wird.
Tags und Links android android-fragments android-configchanges