IllegalStateException, wenn Fragment beim Neustart ersetzen

8

Ich verwende FragmentTransaction.replace() , um Fragmente ein- und auszuwechseln. Die App startet das erste Mal ohne Probleme. Ein IllegalStateException wird beim Drehen des Geräts aufgrund eines Konflikts zwischen savedInstanceState ausgelöst und eine neue Fragmenttransaktion ausführen. Keine AsyncTask ist beteiligt.

Eine StackOverflow-Frage schlägt vor, den Aufruf setContentView() einzufügen in onResumeFragments() , aber das scheint keine Wirkung zu haben. Gleiches mit onPostResume() .

Eine andere StackOverflow-Frage besagt, dass onConfigurationChanged() überschrieben werden soll. Dies funktioniert in dem Sinne, dass es nicht zur Ausnahme kommt weil die Aktivität nicht neu gestartet wird. Dies verhindert jedoch Fragmente mit unterschiedlichem Hochformat und Landschaftslayouts vom Wechsel zwischen diesen Layouts. Aufruf von setContentView() in onConfigurationChanged() verursacht einen ähnlichen Fehler ( IllegalArgumentException: Binäre XML-Dateizeile # 25: ID 0x12345678, Tag null oder übergeordnete ID mit einem anderen Fragment )

Verwendung von fragmentTransaction.commitAllowingStateLoss() anstelle von .commit() Ursachen IllegalStateException: Aktivität wurde zerstört .

Wie bekomme ich das zum Laufen?

Weitere Ausnahmebedingungen:

  

java.lang.RuntimeException: Kann nicht gestartet werden   Aktivität ComponentInfo {myapp / myap.MainActivity}:
  android.view.InflateException: Binäre XML-Datei Zeile # 25: Fehler   Klassenfragment bei   myapp.MainActivity.onResumeFragments (MainActivity.java:450)
  Verursacht von: java.lang.IllegalStateException: Diese Aktion kann nicht nach ausgeführt werden   onSaveInstanceState bei & gt; android.support.v4.app.FragmentManagerImpl.checkStateLoss (FragmentManager.java:1533)   beim   myapp.fragments.FragmentChange.onFragmentChange (FragmentChange.java:128)   beim   myapp.MainActivity.onNavigationDrawerItemSelected (MainActivity.java:490)   beim   myapp.fragments.NavigationDrawerFragment.selectItem (NavigationDrawerFragment.java:197)   beim   myapp.fragments.NavigationDrawerFragment.onCreate (NavigationDrawerFragment.java:78)   bei myapp.MainActivity.onResumeFragments (MainActivity.java:450)

Die Reihenfolge im Code beim Drehen des Geräts ist:

%Vor%

HauptAktivität:

%Vor%

NavigationDrawerFragment

%Vor%

FragmentChange

%Vor%

Ein stark reduziertes Formular des Projekts auf github , das die IllegalStateException wiedergibt:

    
Al Lelopath 16.11.2016, 18:23
quelle

3 Antworten

1

Der FragmentManager ist ein

  

Schnittstelle für die Interaktion mit Fragment-Objekten innerhalb einer Aktivität .

Es scheint mir eine besonders schlechte Idee, es in einem statischen Feld zu speichern und den alten FragmentManager für eine neue Aktivität wiederzuverwenden. Dies führt notwendigerweise zu Aktivität wurde zerstört , wenn die neue Aktivität mit dem Manager aus der alten Aktivität interagiert.

Ersetzen Sie in Ihrem Code

%Vor%

von

%Vor%     
rds 28.11.2016, 20:07
quelle
3

Einige Kommentare :
Ich kann sehen, dass Sie "über und über" hinausgegangen sind, um es zu reparieren (und Stack-Overflow für viele Tipps gescannt haben).
Dein Code funktioniert das erste Mal (auch wenn du in der App startest).
Die Rotation kann das Fragment nicht zum zweiten Mal aufblasen (in activity_main ) und meldet auch den Fehler "commit after save" (das ist seltsam, wie um Himmels willen bekommen wir 2 fatale Fehler? Vielleicht in einem anderen Thread oder " "Save" tötet den Inflator, aber wie kann er weitermachen?).
NavigationDrawerFragment enthält eine Menge wichtigen Code (der normalerweise in der Activity liegt).
Analysis :
Ihre MainActivity class extends AppCompatActivity :

%Vor%

Normalerweise erweitern Sie FragmentActivity :

%Vor%

Dies liegt daran, dass Sie activity_main , das eine fragment enthält, aufblasen.

%Vor%

Vererbung: Aktivität & lt; - FragmentActivity & lt; - AppCompatActivity & lt; - ActionBarActivity
'& lt; -' bedeutet Vererbung hier.
Ein Grund, warum Sie FragmentActivity speziell in Betracht ziehen müssen, ist, wenn Sie verschachtelte Fragmente (ein Fragment, das ein anderes Fragment enthält) verwenden möchten, da dies in nativen Fragmenten erst ab API Level 17 unterstützt wird Ich denke, das machst du hier (in activity_main ):

%Vor%

Hier ist eine gute Vorlage App, die Ihr Leben leichter machen sollte:
android-sliding-menu-using-navigation-drawer /
BEFESTIGUNG :
Ersetzen Sie das Fragment in activity_main.xml durch ListView .
Ich habe NavigationDrawerFragment verworfen und etwas Code aus der obigen Vorlage eingefügt und dann bit-by-bit Ihren Code von NavigationDrawerFragment wieder eingefügt, bis er umfällt. Es funktioniert jetzt mit Rotation, aber nicht so, wie du oder ich es gerne hätten (Erhalt des Fragmentstatus, NavigationDrawerFragment einiger Funktionalität), also arbeite ich noch daran.

protrait

Landschaft nach Rotation

Heißer Tipp : Das .commit klingt final, nicht wahr? Klingt als ob es synchron wäre? Das ist auch nicht wahr.
Das .commit setzt die Transaktion in eine ausstehende Warteschlange, um sie wirklich ausführen zu können, benötigen Sie:

%Vor%

Hier ist ein Link zum Fehlerprotokoll des gebuchten Codes bei der Rotation: Linkfehler log

    
Jon Goodwin 25.11.2016 02:22
quelle
2

Methode 1. Vermeiden Sie Konfigurationsänderungen. Fügen Sie android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|keyboard" in Ihrer Manifest-Aktivität hinzu.

%Vor%

Methode 2. ein. Verpassen Sie als erstes keinen Code von Standard-Orten wie setContentView() in onConfigurationChanged() .
b. Ersetzen Sie das Fragment durch das Tag oder durch die ID in XML
c. Ersetzen Sie nicht erneut, wenn das Fragment von ID oder Tag gefunden wurde.
d. Stellen Sie sicher, dass Sie jeden Dailog innerhalb des Fragments onPause ablehnen.

    
Qamar 25.11.2016 12:31
quelle