Das Fragment wird jedes Mal nach der Änderung der Ausrichtung neu erstellt und kann den Status nicht wiederherstellen

8

Update: Es stellt sich heraus, dass das Problem von anderswo ist. Danke @Luksprog für das Aufzeigen, was ich übersehen habe.

  1. Das Projekt wird mithilfe des Navigationsschubladenmusters von Android Studio erstellt. Die Schublade wird in der Klasse NavigationDrawerFragment implementiert.
  2. Das Fragment, das den Ansichtspager enthält, wird hinzugefügt, wenn ein bestimmtes Element in der Schublade ausgewählt wird. Der Code ist meine Heimaktivität implementiert.
  3. Wenn sich der Bildschirm dreht, wird die Methode onCreate() von NavigationDrawerFragment aufgerufen, wobei das zuletzt ausgewählte Element beibehalten wird.
  4. Und hier ist was schief gelaufen - bei der Wiederherstellung ruft 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:

%Vor%

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).

    
Edmund Tam 24.01.2014, 14:09
quelle

4 Antworten

5

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:

  • Das Projekt wird mithilfe des vom Studio-Assistenten "Projekt erstellen" bereitgestellten Navigationsschubladenmusters erstellt. Die Schublade ist in der Klasse NavigationDrawerFragment implementiert.
  • Das Fragment, das den Ansichtspager enthält, wird hinzugefügt, wenn ein bestimmtes Element in der Schublade ausgewählt wird. Der Code ist meine Heimaktivität implementiert.
  • Wenn sich der Bildschirm dreht, wird die Methode onCreate() von NavigationDrawerFragment aufgerufen, wobei das zuletzt ausgewählte Element beibehalten wird.
  • Und hier ist was falsch gelaufen - bei der Wiederherstellung ruft 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.

    
Edmund Tam 27.01.2014, 09:20
quelle
10

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.

    
Miguel El Merendero 23.10.2014 07:36
quelle
0

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.

%Vor%     
sulai 24.01.2014 14:46
quelle
-2

Fügen Sie in AndroidManifest.xml

hinzu %Vor%     
rad 03.02.2016 10:24
quelle