Einige Benutzer melden, wenn sie die Schnellaktion in der Benachrichtigungsleiste verwenden, wird eine Truppe geschlossen.
Ich zeige eine schnelle Aktion in der Benachrichtigung, die die Klasse "TestDialog" aufruft . In der TestDialog-Klasse wird nach Drücken der Schaltfläche "Snooze" der SnoozeDialog angezeigt.
private View.OnClickListener btnSnoozeOnClick() {
return new View.OnClickListener() {
public void onClick(View v) {
showSnoozeDialog();
}
};
}
private void showSnoozeDialog() {
FragmentManager fm = getSupportFragmentManager();
SnoozeDialog snoozeDialog = new SnoozeDialog();
snoozeDialog.show(fm, "snooze_dialog");
}
Der Fehler ist *IllegalStateException: Can not perform this action after onSaveInstanceState*.
Die Codezeile, in der die IllegarStateException ausgelöst wird, lautet:
snoozeDialog.show(fm, "snooze_dialog");
Die Klasse erweitert "FragmentActivity" und die "SnoozeDialog" -Klasse erweitert "DialogFragment".
Hier ist die vollständige Stapelverfolgung des Fehlers:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1327)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1338)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
at com.test.testing.TestDialog.f(TestDialog.java:538)
at com.test.testing.TestDialog.e(TestDialog.java:524)
at com.test.testing.TestDialog.d(TestDialog.java:519)
at com.test.testing.g.onClick(TestDialog.java:648)
at android.view.View.performClick(View.java:3620)
at android.view.View$PerformClick.run(View.java:14292)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4507)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
Ich kann diesen Fehler nicht reproduzieren, erhalte jedoch viele Fehlerberichte.
Kann mir jemand helfen, wie kann ich diesen Fehler beheben?
Antworten:
Dies ist ein häufiges Problem . Wir haben dieses Problem gelöst, indem wir show () überschrieben und Ausnahmen in der erweiterten Klasse DialogFragment behandelt haben
Beachten Sie, dass durch das Anwenden dieser Methode die internen Felder der DialogFragment.class nicht geändert werden:
Dies kann in einigen Fällen zu unerwarteten Ergebnissen führen. Verwenden Sie besser commitAllowingStateLoss () anstelle von commit ()
quelle
Das bedeutet, dass Sie
commit()
(show()
im Fall von DialogFragment) nach fragmentierenonSaveInstanceState()
.Android speichert Ihren Fragmentstatus unter
onSaveInstanceState()
. Wenn Sie alsocommit()
fragmentieren, geht deronSaveInstanceState()
Fragmentstatus verloren.Wenn Aktivität beendet wird und später neu erstellt wird, wird das Fragment daher nicht zu Aktivitäten hinzugefügt, die eine schlechte Benutzererfahrung darstellen. Deshalb erlaubt Android nicht um jeden Preis den Verlust des Staates.
Die einfache Lösung besteht darin, zu überprüfen, ob der Status bereits gespeichert ist.
Hinweis: onResumeFragments () wird aufgerufen, wenn Fragmente wieder aufgenommen werden.
quelle
ref: link
quelle
Nach wenigen Tagen möchte ich meine Lösung teilen , wie ich es behoben haben, DialogFragment Sie sollten zeigen , außer Kraft zu setzen
show()
Methode davon und rufencommitAllowingStateLoss()
aufTransaction
Objekt. Hier ist ein Beispiel in Kotlin:quelle
DialogFragment
Ihnen erben müssen, können Sie dies in eine Kotlin-Erweiterungsfunktion mit der folgenden Signatur ändern :fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)
. Außerdem ist der Try-Catch nicht erforderlich, da Sie diecommitAllowingStateLoss()
Methode und nicht diecommit()
Methode aufrufen .Wenn der Dialog nicht wirklich wichtig ist (es ist in Ordnung, ihn nicht anzuzeigen, wenn die App geschlossen wird / nicht mehr angezeigt wird), verwenden Sie:
Und öffnen Sie Ihren Dialog (Fragment) nur, wenn wir laufen:
BEARBEITEN, MÖGLICHERWEISE BESSERE LÖSUNG:
Wo onSaveInstanceState im Lebenszyklus aufgerufen wird, ist unvorhersehbar. Ich denke, eine bessere Lösung besteht darin, isSavedInstanceStateDone () wie folgt zu überprüfen:
quelle
Bitte versuchen Sie, FragmentTransaction anstelle von FragmentManager zu verwenden. Ich denke, der folgende Code wird Ihr Problem lösen. Wenn nicht, lassen Sie es mich bitte wissen.
BEARBEITEN:
Fragmenttransaktion
Bitte überprüfen Sie diesen Link. Ich denke, es wird Sie Fragen lösen.
quelle
Ich bin seit Jahren auf dieses Problem gestoßen.
Das Internet ist übersät mit Dutzenden (Hunderttausenden?) Diskussionen darüber, und Verwirrung und Desinformation in ihnen scheinen in Hülle und Fülle vorhanden zu sein.
Um die Situation noch schlimmer zu machen und im Geiste des xkcd-Comics "14 Standards", werfe ich meine Antwort in den Ring.
Die
cancelPendingInputEvents()
,commitAllowingStateLoss()
,catch (IllegalStateException e)
und ähnliche Lösungen scheinen alle scheußlich.Hoffentlich zeigt das Folgende leicht, wie das Problem reproduziert und behoben werden kann:
quelle
Die Verwendung der neuen Lebenszyklusbereiche von Activity-KTX ist so einfach wie das folgende Codebeispiel:
Diese Methode kann direkt nach onStop () aufgerufen werden und zeigt den Dialog erfolgreich an, sobald onResume () bei der Rückkehr aufgerufen wurde.
quelle
In vielen Ansichten werden Ereignisse auf hoher Ebene, z. B. Klick-Handler, in die Ereigniswarteschlange gestellt, um sie verzögert auszuführen. Das Problem ist also, dass "onSaveInstanceState" bereits für die Aktivität aufgerufen wurde, die Ereigniswarteschlange jedoch ein verzögertes "Klickereignis" enthält. Daher, wenn dieses Ereignis an Ihren Handler gesendet wird
und Ihr Code führt
show
die IllegalStateException aus.Die einfachste Lösung besteht darin, die Ereigniswarteschlange in zu bereinigen
onSaveInstanceState
quelle
activity
undfragment
) befinden.Machen Sie Ihr Dialogfragmentobjekt global und rufen Sie entlassenAllowingStateLoss () in der Methode onPause () auf
Vergessen Sie nicht, den Wert in Fragment zuzuweisen und show () beim Klicken auf die Schaltfläche oder wo auch immer aufzurufen.
quelle
Es wird zwar nirgendwo offiziell erwähnt, aber ich habe mich ein paar Mal mit diesem Problem befasst. Nach meiner Erfahrung stimmt etwas in der Kompatibilitätsbibliothek nicht, die Fragmente auf älteren Plattformen unterstützt, was dieses Problem verursacht. Sie verwenden dies, indem Sie die normale Fragmentmanager-API verwenden. Wenn nichts funktioniert, können Sie den normalen Dialog anstelle des Dialogfragments verwenden.
quelle
Verwenden Sie die Methode showAllowingStateLoss anstelle von show
Genießen ;)
quelle
StatelessDialogFragment
in eines meiner Pakete gesteckt habe. Danke, Alter. Ich werde es bald in der Produktion testen.Verwenden Sie diesen Code
anstatt
quelle
Ich habe eine elegante Lösung für dieses Problem gefunden, indem ich Reflexion verwendet habe. Das Problem aller oben genannten Lösungen ist, dass die Felder mDismissed und mShownByMe ihren Status nicht ändern.
Überschreiben Sie einfach die Methode "show" in Ihrem eigenen benutzerdefinierten Dialogfragment für das untere Blatt, wie im folgenden Beispiel (Kotlin).
quelle
Die folgende Implementierung kann verwendet werden, um das Problem der Durchführung sicherer Statusänderungen während des
Activity
Lebenszyklus zu lösen , insbesondere um Dialoge anzuzeigen: Wenn der Instanzstatus bereits gespeichert wurde (z. B. aufgrund einer Konfigurationsänderung), werden sie verschoben, bis der wieder aufgenommene Status vorliegt durchgeführt wurde.Dann benutze eine Klasse wie diese:
Sie können Dialoge sicher anzeigen, ohne sich über den App-Status Gedanken machen zu müssen:
und rufen
TestDialog.show(this)
Sie dann aus IhremXAppCompatActivity
.Wenn Sie eine allgemeinere Dialogklasse mit Parametern erstellen möchten, können Sie diese in a
Bundle
mit den Argumenten in dershow()
Methode speichern und mitgetArguments()
in abrufenonCreateDialog()
.Der gesamte Ansatz mag etwas komplex erscheinen, aber sobald Sie die beiden Basisklassen für Aktivitäten und Dialoge erstellt haben, ist er recht einfach zu verwenden und funktioniert einwandfrei. Es kann für andere
Fragment
basierte Vorgänge verwendet werden, die von demselben Problem betroffen sein können.quelle
Dieser Fehler scheint aufzutreten, weil Eingabeereignisse (z. B. Key-Down- oder On-Click-Ereignisse) nach dem
onSaveInstanceState
Aufruf übermittelt werden .Die Lösung besteht darin,
onSaveInstanceState
Ihre Aktivität zu überschreiben und ausstehende Ereignisse abzubrechen.quelle