Ich habe eine Live-Android-Anwendung, und vom Markt habe ich folgende Stapelverfolgung erhalten, und ich habe keine Ahnung, warum dies geschieht, da es nicht im Anwendungscode geschieht, sondern durch das eine oder andere Ereignis aus der Anwendung verursacht wird (Annahme)
Ich verwende keine Fragmente, dennoch gibt es eine Referenz von FragmentManager. Wenn jemand etwas Licht auf versteckte Fakten werfen kann, um diese Art von Problem zu vermeiden:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1109)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:399)
at android.app.Activity.onBackPressed(Activity.java:2066)
at android.app.Activity.onKeyDown(Activity.java:1962)
at android.view.KeyEvent.dispatch(KeyEvent.java:2482)
at android.app.Activity.dispatchKeyEvent(Activity.java:2274)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1112)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1720)
at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1258)
at android.app.Activity.dispatchKeyEvent(Activity.java:2269)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1668)
at android.view.ViewRoot.deliverKeyEventPostIme(ViewRoot.java:2851)
at android.view.ViewRoot.handleFinishedEvent(ViewRoot.java:2824)
at android.view.ViewRoot.handleMessage(ViewRoot.java:2011)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:132)
at android.app.ActivityThread.main(ActivityThread.java:4025)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Antworten:
Dies ist der dümmste Fehler, dem ich bisher begegnet bin. Ich hatte eine
Fragment
Anwendung, die perfekt für API <11 undForce Closing
für API> 11 funktionierte .Ich konnte wirklich nicht herausfinden, was sie innerhalb des
Activity
Lebenszyklus des Aufrufs an geändert habensaveInstance
, aber hier ist, wie ich das gelöst habe:Ich rufe einfach nicht an
.super()
und alles funktioniert super. Ich hoffe, das spart Ihnen etwas Zeit.BEARBEITEN: Nach einigen weiteren Recherchen ist dies ein bekannter Fehler im Support-Paket.
Wenn Sie die Instanz speichern und etwas zu Ihrer hinzufügen müssen, können
outState
Bundle
Sie Folgendes verwenden:EDIT2: Dies kann auch auftreten, wenn Sie versuchen, eine Transaktion auszuführen, nachdem Sie
Activity
im Hintergrund verschwunden sind. Um dies zu vermeiden, sollten Sie verwendencommitAllowingStateLoss()
EDIT3: Die oben genannten Lösungen haben Probleme in den frühen support.v4-Bibliotheken behoben, soweit ich mich erinnern kann. Aber wenn Sie immer noch Probleme mit diesem haben Sie MÜSSEN auch lesen @AlexLockwood : ‚s Blog Fragment Transaktionen & Aktivitätszustand Verlust
Zusammenfassung aus dem Blog-Beitrag (aber ich empfehle Ihnen dringend, ihn zu lesen):
commit()
Transaktionen nachonPause()
Pre-Honeycomb undonStop()
Post-HoneycombActivity
Lebenszyklusmethoden ausführen. VerwendungonCreate()
,onResumeFragments()
undonPostResume()
commitAllowingStateLoss()
nur als letztes Mittelquelle
commitAllowingStateLoss()
vermeidet nur die Ausnahme. Es schützt Ihre Anwendung nicht vor versehentlichem Statusverlust. Siehe diesen Blog-Beitrag .Wenn Sie im Android-Quellcode nach den Ursachen dieses Problems suchen, hat das Flag mStateSaved in
FragmentManagerImpl
class (Instanz in Activity verfügbar) den Wert true. Es wird auf true gesetzt, wenn der Backstack beim Aufruf von gespeichert wird (saveAllState)Activity#onSaveInstanceState
. Danach setzen die Aufrufe von ActivityThread dieses Flag nicht mit den verfügbaren Rücksetzmethoden vonFragmentManagerImpl#noteStateNotSaved()
und zurückdispatch()
.So wie ich es sehe, gibt es einige verfügbare Korrekturen, je nachdem, was Ihre App tut und verwendet:
Gute Wege
Vor allem: Ich würde für Alex Lockwood Artikel werben . Dann von dem, was ich bisher gemacht habe:
Rufen Sie für Fragmente und Aktivitäten, für die keine Statusinformationen erforderlich sind , commitAllowStateLoss auf . Entnommen aus der Dokumentation:
commit()
Rufen Sie kurz nach dem Festschreiben der Transaktion (Sie haben gerade angerufen ) anFragmentManager.executePendingTransactions()
.Nicht empfohlene Methoden:
Wie Ovidiu Latcu oben erwähnt hat, rufen Sie nicht an
super.onSaveInstanceState()
. Dies bedeutet jedoch, dass Sie den gesamten Status Ihrer Aktivität zusammen mit dem Fragmentstatus verlieren.Überschreiben
onBackPressed
und nur dort anrufenfinish()
. Dies sollte in Ordnung sein, wenn Ihre Anwendung die Fragment-API nicht verwendet. wie insuper.onBackPressed
gibt es einen anruf anFragmentManager#popBackStackImmediate()
.Wenn Sie beide Fragment-APIs verwenden und der Status Ihrer Aktivität wichtig / wichtig ist, können Sie versuchen, mithilfe der Reflection-API aufzurufen
FragmentManagerImpl#noteStateNotSaved()
. Aber dies ist ein Hack, oder man könnte sagen, es ist eine Problemumgehung. Ich mag es nicht, aber in meinem Fall ist es ziemlich akzeptabel, da ich einen Code aus einer Legacy-App habe, der (TabActivity
und implizitLocalActivityManager
) veralteten Code verwendet .Unten ist der Code, der Reflektion verwendet:
Prost!
quelle
Eine solche Ausnahme tritt auf, wenn Sie versuchen, einen Fragmentübergang durchzuführen, nachdem Ihre Fragmentaktivität
onSaveInstanceState()
aufgerufen wurde.Ein Grund dafür kann sein, dass Sie ein
AsyncTask
(oderThread
) laufen lassen, wenn eine Aktivität gestoppt wird.Übergänge nach dem
onSaveInstanceState()
Aufruf können möglicherweise verloren gehen, wenn das System die Aktivität für Ressourcen zurückfordert und sie später neu erstellt.quelle
super.onSaveInstanceState()
.Rufen Sie einfach super.onPostResume () auf, bevor Sie Ihr Fragment anzeigen, oder verschieben Sie Ihren Code nach dem Aufruf von super.onPostResume () in die Methode onPostResume (). Dies löst das Problem!
quelle
Dies kann auch passieren, wenn
dismiss()
ein Dialogfragment aufgerufen wird, nachdem der Bildschirm gesperrt und ausgeblendet und der Instanzstatus des Dialogfelds Aktivität + gespeichert wurde. Um diesen Anruf zu umgehen:Buchstäblich jedes Mal, wenn ich einen Dialog entlasse, ist mir der Status sowieso egal, also ist das in Ordnung - Sie verlieren eigentlich keinen Status.
quelle
Kurze und funktionierende Lösung:
Befolgen Sie einfache Schritte:
Schritt 1 : Überschreiben Sie den onSaveInstanceState-Status im jeweiligen Fragment. Und entfernen Sie die Super-Methode daraus.
Schritt 2 : Verwenden Sie CommitAllowingStateLoss (); anstelle von commit (); während Fragmentoperationen.
quelle
Ich denke, der Lifecycle-Status kann helfen, einen solchen Absturz ab der Android-Unterstützung lib v26.1.0 zu verhindern. Sie können die folgende Überprüfung durchführen lassen:
oder Sie können versuchen:
Weitere Informationen finden Sie hier https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()
quelle
das hat bei mir funktioniert ... habe das selbst herausgefunden ... hoffe es hilft dir!
1) keinen globalen "statischen" FragmentManager / FragmentTransaction haben.
2) onCreate initialisiert den FragmentManager IMMER erneut!
Beispiel unten: -
quelle
Ich habe das immer bekommen, wenn ich versucht habe, ein Fragment in der onActivityForResult () -Methode anzuzeigen, also war das Problem das nächste:
Was ich gemacht habe ist als nächstes:
quelle
Ich habe das Problem mit onconfigurationchanged gelöst. Der Trick ist, dass je nach Lebenszyklus der Android-Aktivität, wenn Sie explizit eine Absicht (Kameraabsicht oder eine andere) genannt haben; In diesem Fall wird die Aktivität angehalten und onsavedInstance aufgerufen. Wenn Sie das Gerät in eine andere Position als die drehen, in der die Aktivität aktiv war; Das Ausführen von Fragmentoperationen wie Fragment Commit führt zu einer Ausnahme für den unzulässigen Status. Es gibt viele Beschwerden darüber. Es geht um das Management des Lebenszyklus von Android-Aktivitäten und um richtige Methodenaufrufe. Um dies zu lösen, habe ich Folgendes getan: 1-Überschreiben Sie die onsavedInstance-Methode Ihrer Aktivität und bestimmen Sie die aktuelle Bildschirmausrichtung (Hoch- oder Querformat). Stellen Sie dann Ihre Bildschirmausrichtung darauf ein, bevor Ihre Aktivität angehalten wird. Auf diese Weise sperren Sie die Bildschirmdrehung für Ihre Aktivität, falls sie von einer anderen gedreht wurde. 2-dann überschreiben Sie die Wiederaufnahme der Aktivitätsmethode und stellen Sie Ihren Orientierungsmodus jetzt auf Sensor ein, sodass nach dem Aufrufen der gespeicherten Methode eine weitere Konfiguration aufgerufen wird, um die Rotation ordnungsgemäß zu verarbeiten.
Sie können diesen Code kopieren / in Ihre Aktivität einfügen, um damit umzugehen:
quelle
Ich hatte das gleiche Problem, IllegalStateException zu erhalten, aber das Ersetzen aller meiner Aufrufe von commit () durch commitAllowingStateLoss () hat nicht geholfen.
Der Schuldige war ein Aufruf von DialogFragment.show ().
Ich umgebe es mit
und das hat es geschafft. OK, ich kann den Dialog nicht anzeigen, aber in diesem Fall war das in Ordnung.
Es war der einzige Ort in meiner App, an dem ich FragmentManager.beginTransaction () zum ersten Mal aufgerufen habe, aber nie commit () aufgerufen habe. Daher habe ich es nicht gefunden, als ich nach "commit ()" gesucht habe.
Das Lustige ist, dass der Benutzer die App nie verlässt. Stattdessen war der Killer eine AdMob-Interstitial-Anzeige.
quelle
Meine Lösung für dieses Problem war
Fügen Sie im Fragment Methoden hinzu:
Mag schlecht sein, konnte aber nichts Besseres finden.
quelle
Ich habe dieses Problem. Aber ich denke, dieses Problem hängt nicht mit Commit und CommitAllowStateLoss zusammen.
Die folgende Stack-Trace- und Ausnahmemeldung befasst sich mit commit ().
Diese Ausnahme wurde jedoch durch onBackPressed () verursacht.
Sie wurden alle von checkStateLoss () verursacht
mStateSaved ist nach onSaveInstanceState wahr.
Dieses Problem tritt selten auf. Ich bin noch nie auf dieses Problem gestoßen. Ich kann das Problem nicht erneut auftreten.
Ich habe das Problem 25517 gefunden
Dies kann unter folgenden Umständen geschehen sein
Die Zurück-Taste wird nach onSaveInstanceState aufgerufen, jedoch bevor die neue Aktivität gestartet wird.
Verwenden Sie onStop () im Code
Ich bin mir nicht sicher, wo die Wurzel des Problems liegt. Also habe ich einen hässlichen Weg benutzt.
quelle
Ich habe das gleiche Problem in meiner App. Ich habe dieses Problem gelöst, indem ich nur die
super.onBackPressed();
vorherige Klasse undcommitAllowingStateLoss()
die aktuelle Klasse mit diesem Fragment aufgerufen habe.quelle
commitAllowingStateLoss()
anstelle voncommit()
onSaveInstance wird aufgerufen, wenn ein Benutzer den Bildschirm dreht, damit er Ressourcen laden kann, die der neuen Ausrichtung zugeordnet sind.
Es ist möglich, dass dieser Benutzer den Bildschirm gedreht und anschließend die Zurück-Taste gedrückt hat (da dieser Benutzer möglicherweise auch sein Telefon während der Verwendung Ihrer App gefummelt hat).
quelle
Lesen Sie http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
Artikel. Die Überprüfung von fragment.isResumed () hilft mir bei onDestroyView ohne Verwendung der onSaveInstanceState-Methode.
quelle
Gleiches Problem von mir und nach einem Tag Analyse aller Artikel, Blogs und Stackoverflow habe ich eine einfache Lösung gefunden. Verwenden Sie savedInstanceState überhaupt nicht. Dies ist die Bedingung mit einer Codezeile. Auf dem Fragmentcode:
quelle
Dies geschieht immer dann, wenn Sie versuchen, ein Fragment zu laden, die Aktivität jedoch ihren Status in onPause () geändert hat. Dies geschieht beispielsweise, wenn Sie versuchen, Daten abzurufen und in die Aktivität zu laden, aber bis der Benutzer auf eine Schaltfläche geklickt hat und dies getan hat zur nächsten Aktivität übergegangen.
Sie können dies auf zwei Arten lösen
Sie können transaction.commitAllowingStateLoss () anstelle von transaction.commit () verwenden, um das Fragment zu laden. Möglicherweise verlieren Sie jedoch den durchgeführten Commit-Vorgang.
oder
Stellen Sie sicher, dass die Aktivität fortgesetzt wird und der Status beim Laden eines Fragments nicht angehalten wird. Erstellen Sie einen Booleschen Wert und prüfen Sie, ob die Aktivität nicht in den Status onPause () wechselt.
Überprüfen Sie dann beim Laden des Fragments, ob Aktivität vorhanden ist, und laden Sie es nur, wenn die Aktivität im Vordergrund steht.
quelle
Danke @gunar, aber ich denke, es gibt einen besseren Weg.
Laut doc:
Verwenden Sie also
commitNow
, um Folgendes zu ersetzen:quelle
Nun, nachdem ich alle oben genannten Lösungen ohne Erfolg ausprobiert habe (weil ich im Grunde keine Transaktionen habe).
In meinem Fall habe ich AlertDialogs und ProgressDialog als Fragmente verwendet, bei denen manchmal bei Rotation, wenn ich nach dem FragmentManager frage, der Fehler auftritt.
Ich habe eine Problemumgehung gefunden, bei der viele ähnliche Beiträge gemischt wurden:
Es handelt sich um eine dreistufige Lösung, die alle auf Ihrer FragmentActivity ausgeführt wird (in diesem Fall GenericActivity):
quelle
Wenn ich Startaktivität in einem Fragment verwende, erhalte ich diese Ausnahme;
Wenn ich startactivityforresult ändere, ist die Ausnahme weg :)
Der einfachste Weg, dies zu beheben, ist die Verwendung der API startActivityForResult :)
quelle
Ich habe diese Ausnahme erhalten, als ich die Zurück-Taste gedrückt habe, um die Absichtsauswahl für meine Kartenfragmentaktivität abzubrechen. Ich habe dieses Problem behoben, indem ich den Code von onResume () (wo ich das Fragment initialisiert und die Transaktion festgeschrieben habe) durch onStart () ersetzt habe. Die App funktioniert jetzt einwandfrei. Ich hoffe es hilft.
quelle
Dies ist in Android 4.2 und auch in der Quelle der Support-Bibliothek behoben. [*]
Einzelheiten zur Ursache (und zu den Problemumgehungen) finden Sie im Google-Fehlerbericht: http://code.google.com/p/android/issues/detail?id=19917
Wenn Sie die Support-Bibliothek verwenden, sollten Sie sich (lange) keine Sorgen um diesen Fehler machen müssen [*]. Wenn Sie die API jedoch direkt verwenden (dh den FragmentManager der Support-Bibliothek nicht verwenden) und auf eine API unter Android 4.2 abzielen, müssen Sie eine der Problemumgehungen ausprobieren.
[*] Zum Zeitpunkt des Schreibens verteilt der Android SDK Manager noch eine alte Version, die diesen Fehler aufweist.
Bearbeiten Ich werde hier einige Klarstellungen hinzufügen, da ich offensichtlich irgendwie verwirrt habe, wer diese Antwort abgelehnt hat.
Es gibt verschiedene (aber verwandte) Umstände, die dazu führen können, dass diese Ausnahme ausgelöst wird . Meine obige Antwort bezieht sich auf die spezifische Instanz, die in der Frage besprochen wurde, dh einen Fehler in Android, der später behoben wurde. Wenn Sie diese Ausnahme aus einem anderen Grund erhalten, liegt dies daran, dass Sie Fragmente hinzufügen / entfernen, wenn dies nicht der Fall sein sollte (nachdem Fragmentzustände gespeichert wurden). Wenn Sie sich in einer solchen Situation befinden, kann Ihnen möglicherweise " Verschachtelte Fragmente - IllegalStateException" Diese Aktion kann nach onSaveInstanceState nicht ausgeführt werden " von Nutzen sein.
quelle
Nachdem Sie ein wenig recherchiert haben, besteht die Lösung für dieses Problem darin, Ihre Fragment-Commits im Onresume durchzuführen.
Quelle: https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/
quelle
Mein Anwendungsfall: Ich habe Listener in Fragment verwendet, um Aktivitäten darüber zu informieren, dass etwas passiert ist. Ich habe ein neues Fragment-Commit für die Rückrufmethode durchgeführt. Dies funktioniert beim ersten Mal einwandfrei. Bei einer Änderung der Ausrichtung wird die Aktivität jedoch mit dem gespeicherten Instanzstatus neu erstellt. In diesem Fall wird das Fragment nicht erneut erstellt, was bedeutet, dass das Fragment den Listener hat, bei dem es sich um eine alte zerstörte Aktivität handelt. Auf jede Art und Weise wird die Rückrufmethode bei einer Aktion ausgelöst. Es geht um zerstörte Aktivitäten, die das Problem verursachen. Die Lösung besteht darin, den Listener fragmentarisch mit der aktuellen Live-Aktivität zurückzusetzen. Dies löst das Problem.
quelle
Ich habe festgestellt, dass fast jede Hintergrund-App mit diesem Fehler abstürzt, wenn eine andere App vom Typ Dialog ist und das Senden von Berührungen an die Hintergrund-App ermöglicht. Ich denke, wir müssen jedes Mal überprüfen, wenn eine Transaktion ausgeführt wird, ob die Instanz gespeichert oder wiederhergestellt wurde.
quelle
In meinem Fall habe ich mit der gleichen Fehlerausnahme "onBackPressed ()" in eine ausführbare Datei eingefügt (Sie können jede Ihrer Ansichten verwenden):
Ich verstehe nicht warum, aber es funktioniert!
quelle
Möglicherweise rufen Sie fragmentManager.popBackStackImmediate () auf. wenn die Aktivität unterbrochen ist. Die Aktivität ist noch nicht beendet, wird jedoch angehalten und steht nicht im Vordergrund. Sie müssen vor popBackStackImmediate () überprüfen, ob die Aktivität angehalten wurde oder nicht.
quelle
Mir ist etwas sehr Interessantes aufgefallen. Ich habe in meiner App die Möglichkeit, die Galerie des Telefons zu öffnen, und das Gerät fragt, welche App verwendet werden soll. Dort klicke ich auf den grauen Bereich außerhalb des Dialogfelds und sehe dieses Problem. Ich habe festgestellt, wie meine Aktivität von onPause, onSaveInstanceState zurück zu onResume geht. OnCreateView wird nicht besucht. Ich mache Transaktionen bei onResume. Am Ende habe ich ein Flag gesetzt, das in Pause negiert wird, in CreateView jedoch wahr ist. Wenn das Flag onResume true ist, führen Sie onCommit aus, andernfalls commitAllowingStateLoss. Ich könnte so viel Zeit verschwenden, aber ich wollte den Lebenszyklus überprüfen. Ich habe ein Gerät, das sdkversion 23 ist, und ich bekomme dieses Problem nicht, aber ich habe ein anderes, das 21 ist, und dort sehe ich es.
quelle
Sie können FragmentActivity.onStart vor popBackStackImmediate verwenden
so was:
http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html
quelle