Certains utilisateurs signalent, s'ils utilisent l'action rapide dans la barre de notification, ils obtiennent une fermeture forcée.
Je montre une action rapide dans la notification qui appelle la classe "TestDialog" . Dans la classe TestDialog après avoir appuyé sur le bouton "snooze", je vais afficher le SnoozeDialog.
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");
}
L'erreur est *IllegalStateException: Can not perform this action after onSaveInstanceState*.
La ligne de code où l'exception IllegarStateException est déclenchée est:
snoozeDialog.show(fm, "snooze_dialog");
La classe étend "FragmentActivity" et la classe "SnoozeDialog" étend "DialogFragment".
Voici la trace de pile complète de l'erreur:
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)
Je ne peux pas reproduire cette erreur, mais je reçois beaucoup de rapports d'erreur.
Quelqu'un peut-il m'aider, comment puis-je corriger cette erreur?
Réponses:
C'est un problème courant . Nous avons résolu ce problème en remplaçant show () et en gérant l'exception dans la classe étendue DialogFragment
Notez que l'application de cette méthode ne modifiera pas les champs internes de DialogFragment.class:
Cela peut conduire à des résultats inattendus dans certains cas. Mieux vaut utiliser commitAllowingStateLoss () au lieu de commit ()
la source
Cela signifie que vous
commit()
(show()
dans le cas de DialogFragment) fragmentez aprèsonSaveInstanceState()
.Android enregistrera votre état de fragment à
onSaveInstanceState()
. Donc, si vouscommit()
fragmentez après, l'onSaveInstanceState()
état du fragment sera perdu.En conséquence, si l'activité est supprimée et recrée plus tard, le fragment ne s'ajoutera pas à l'activité, ce qui est une mauvaise expérience utilisateur. C'est pourquoi Android ne permet pas à tout prix la perte d'état.
La solution simple est de vérifier si l'état est déjà enregistré.
Remarque: onResumeFragments () appellera lorsque les fragments reprendront.
la source
ref: lien
la source
Après quelques jours , je veux partager ma solution que je l' ai fixé, de le montrer DialogFragment vous devriez passer outre la
show()
méthode de celui - ci et appelercommitAllowingStateLoss()
sur l'Transaction
objet. Voici un exemple à Kotlin:la source
DialogFragment
vous pourriez changer cela pour être une fonction d'extension Kotlin avec la signature suivante:fun DialogFragment.showAllowingStateLoss(fragmentManager: FragmentManager, tag: String)
. De plus, le try-catch n'est pas nécessaire puisque vous appelez lacommitAllowingStateLoss()
méthode et non lacommit()
méthode.Si la boîte de dialogue n'est pas vraiment importante (vous pouvez ne pas l'afficher lorsque l'application est fermée / n'est plus visible), utilisez:
Et ouvrez votre boîte de dialogue (fragment) uniquement lorsque nous sommes en cours d'exécution:
EDIT, PROBABLEMENT MEILLEURE SOLUTION:
Là où onSaveInstanceState est appelé dans le cycle de vie est imprévisible, je pense qu'une meilleure solution consiste à vérifier isSavedInstanceStateDone () comme ceci:
la source
Je suis confronté à ce problème depuis des années.
Les internets sont jonchés de dizaines (des centaines? Des milliers?) De discussions à ce sujet, et la confusion et la désinformation y semblent abondantes.
Pour aggraver la situation, et dans l'esprit de la bande dessinée xkcd "14 standards", je jette ma réponse sur le ring.
Le
cancelPendingInputEvents()
,commitAllowingStateLoss()
,catch (IllegalStateException e)
, et des solutions similaires semblent tout atroce.Espérons que ce qui suit montre facilement comment reproduire et résoudre le problème:
la source
essayez d'utiliser FragmentTransaction au lieu de FragmentManager. Je pense que le code ci-dessous résoudra votre problème. Sinon, faites-le moi savoir.
ÉDITER:
Transaction de fragment
Veuillez vérifier ce lien. Je pense que cela résoudra vos questions.
la source
L'utilisation des nouvelles étendues de cycle de vie d'Activity-KTX est aussi simple que l'exemple de code suivant:
Cette méthode peut être directement appelée après onStop () et affichera avec succès la boîte de dialogue une fois que onResume () a été appelé au retour.
la source
De nombreuses vues publient des événements de haut niveau tels que des gestionnaires de clics dans la file d'attente d'événements pour une exécution différée. Le problème est donc que "onSaveInstanceState" a déjà été appelé pour l'activité mais que la file d'attente d'événements contient un "événement de clic" différé. Par conséquent, lorsque cet événement est envoyé à votre gestionnaire
et votre code fait,
show
l'exception IllegalStateException est levée.La solution la plus simple consiste à nettoyer la file d'attente d'événements, en
onSaveInstanceState
la source
activity
etfragment
).Rendez votre objet de fragment de boîte de dialogue global et appelez rejeterAllowingStateLoss () dans la méthode onPause ()
N'oubliez pas d'attribuer une valeur dans le fragment et d'appeler show () en cliquant sur le bouton ou ailleurs.
la source
Bien que ce ne soit officiellement mentionné nulle part, j'ai été confronté à ce problème plusieurs fois. D'après mon expérience, il y a quelque chose qui ne va pas dans la bibliothèque de compatibilité prenant en charge des fragments sur des plates-formes plus anciennes qui provoque ce problème. Vous utilisez le test en utilisant l'API normale du gestionnaire de fragments. Si rien ne fonctionne, vous pouvez utiliser la boîte de dialogue normale au lieu du fragment de boîte de dialogue.
la source
Utilisez la méthode showAllowingStateLoss au lieu de show
Prendre plaisir ;)
la source
StatelessDialogFragment
dans l'un de mes packages.Merci mec, je vais le tester en production bientôt.utiliser ce code
au lieu de
la source
J'ai trouvé une solution élégante à ce problème en utilisant la réflexion. Le problème de toutes les solutions ci-dessus est que les champs mDismissed et mShownByMe ne changent pas d'état.
Remplacez simplement la méthode "show" dans votre propre fragment de dialogue de feuille de fond personnalisé comme l'exemple ci-dessous (Kotlin)
la source
L'implémentation suivante peut être utilisée pour résoudre le problème de l'exécution en toute sécurité des changements d'état au cours du
Activity
cycle de vie, en particulier pour afficher les boîtes de dialogue: si l'état de l'instance a déjà été enregistré (par exemple en raison d'un changement de configuration), il les reporte jusqu'à ce que l'état repris ait été effectuée.Puis en utilisant une classe comme celle-ci:
Vous pouvez afficher les boîtes de dialogue en toute sécurité sans vous soucier de l'état de l'application:
puis appelez
TestDialog.show(this)
depuis votreXAppCompatActivity
.Si vous souhaitez créer une classe de dialogue plus générique avec des paramètres, vous pouvez les enregistrer dans un
Bundle
avec les arguments de lashow()
méthode et les récupérer avecgetArguments()
inonCreateDialog()
.L'approche dans son ensemble peut sembler un peu complexe, mais une fois que vous avez créé les deux classes de base pour les activités et les dialogues, elle est assez facile à utiliser et fonctionne parfaitement. Il peut être utilisé pour d'autres
Fragment
opérations basées qui pourraient être affectées par le même problème.la source
Cette erreur semble se produire car les événements d'entrée (tels que les événements de touche enfoncée ou de clic) sont livrés après l'
onSaveInstanceState
appel.La solution consiste à remplacer
onSaveInstanceState
votre activité et à annuler tous les événements en attente.la source