J'ai une application Android en direct, et du marché, j'ai reçu la trace de pile suivante et je ne sais pas pourquoi cela se produit car cela ne se produit pas dans le code de l'application mais est provoqué par un ou l'autre événement de l'application (hypothèse)
Je n'utilise pas Fragments, il y a toujours une référence de FragmentManager. Si un organisme peut éclairer certains faits cachés pour éviter ce type de problème:
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)
Réponses:
C'est le bug le plus stupide que j'ai rencontré jusqu'à présent. J'avais une
Fragment
application fonctionnant parfaitement pour API <11 etForce Closing
sur API> 11 .Je ne pouvais vraiment pas comprendre ce qu'ils avaient changé dans le
Activity
cycle de vie lors de l'appel àsaveInstance
, mais voici comment j'ai résolu ce problème:Je ne fais tout simplement pas l'appel à
.super()
et tout fonctionne très bien. J'espère que cela vous fera gagner du temps.EDIT: après quelques recherches supplémentaires, il s'agit d'un bug connu dans le package de support.
Si vous devez enregistrer l'instance et ajouter quelque chose à votre,
outState
Bundle
vous pouvez utiliser ce qui suit:EDIT2: cela peut également se produire si vous essayez d'effectuer une transaction après avoir
Activity
disparu en arrière-plan. Pour éviter cela, vous devez utilisercommitAllowingStateLoss()
EDIT3: Les solutions ci-dessus corrigeaient des problèmes dans les premières bibliothèques support.v4 de ce dont je me souviens. Mais si vous avez encore des problèmes avec cela, vous DEVEZ également lire le blog de @AlexLockwood : Transactions de fragments et perte d'état d'activité
Résumé du billet de blog (mais je vous recommande fortement de le lire):
commit()
transactions aprèsonPause()
sur pré-Honeycomb etonStop()
sur post-HoneycombActivity
méthodes de cycle de vie. UtiliseronCreate()
,onResumeFragments()
etonPostResume()
commitAllowingStateLoss()
uniquement en dernier recoursla source
commitAllowingStateLoss()
n'évite que l'exception. Il ne protège pas votre application d'une perte d'état accidentelle. Voir cet article de blog .La recherche dans le code source Android sur les causes de ce problème donne à l'indicateur mStateSaved dans la
FragmentManagerImpl
classe (instance disponible dans Activity) la valeur true. Il est défini sur true lorsque la pile arrière est enregistrée (saveAllState) à l'appel deActivity#onSaveInstanceState
. Ensuite, les appels d'ActivityThread ne réinitialisent pas cet indicateur en utilisant les méthodes de réinitialisation disponibles à partir deFragmentManagerImpl#noteStateNotSaved()
etdispatch()
.Selon moi, il existe des correctifs disponibles, selon ce que fait et utilise votre application:
De bonnes manières
Avant toute chose: j'annoncerais un article d'Alex Lockwood . Ensuite, d'après ce que j'ai fait jusqu'à présent:
Pour les fragments et activités qui n'ont pas besoin de conserver d'informations sur l'état, appelez commitAllowStateLoss . Tiré de la documentation:
Juste après la validation de la transaction (vous venez d'appeler
commit()
), appelezFragmentManager.executePendingTransactions()
.Moyens non recommandés:
Comme Ovidiu Latcu l'a mentionné ci-dessus, n'appelez pas
super.onSaveInstanceState()
. Mais cela signifie que vous perdrez tout l'état de votre activité ainsi que l'état des fragments.Remplacer
onBackPressed
et appeler là uniquementfinish()
. Cela devrait être OK si votre application n'utilise pas l'API Fragments; commesuper.onBackPressed
il y a un appel àFragmentManager#popBackStackImmediate()
.Si vous utilisez à la fois l'API Fragments et que l'état de votre activité est important / vital, vous pouvez essayer d'appeler à l'aide de l'API de réflexion
FragmentManagerImpl#noteStateNotSaved()
. Mais c'est un hack, ou on pourrait dire que c'est une solution de contournement. Je n'aime pas ça, mais dans mon cas, c'est tout à fait acceptable car j'ai un code d'une application héritée qui utilise du code obsolète (TabActivity
et implicitementLocalActivityManager
).Voici le code qui utilise la réflexion:
À votre santé!
la source
Une telle exception se produira si vous essayez d'effectuer une transition de fragment après l'
onSaveInstanceState()
appel de l' activité de votre fragment .Une des raisons pour lesquelles cela peut se produire est que vous laissez un
AsyncTask
(ouThread
) courir quand une activité s'arrête.Toute transition après l'
onSaveInstanceState()
appel est potentiellement perdue si le système récupère l'activité pour les ressources et la recrée plus tard.la source
super.onSaveInstanceState()
.Appelez simplement super.onPostResume () avant d'afficher votre fragment ou déplacez votre code dans la méthode onPostResume () après avoir appelé super.onPostResume (). Cela résout le problème!
la source
Cela peut également se produire lorsque vous appelez
dismiss()
un fragment de boîte de dialogue après que l'écran a été verrouillé \ vide et que l'état de l'instance de la boîte de dialogue Activity + a été enregistré. Pour contourner cet appel:Littéralement chaque fois que je rejette une boîte de dialogue, je ne me soucie plus de son état de toute façon, donc c'est ok à faire - vous ne perdez en fait aucun état.
la source
Solution courte et fonctionnelle:
Suivez les étapes simples:
Étape 1 : remplacer l'état onSaveInstanceState dans le fragment respectif. Et supprimez la super méthode.
Étape 2 : utilisez CommitAllowingStateLoss (); au lieu de commit (); tandis que les opérations de fragment.
la source
Je pense que l'état du cycle de vie peut aider à empêcher un tel crash à partir de la prise en charge d'Android lib v26.1.0, vous pouvez avoir la vérification suivante:
ou vous pouvez essayer:
plus d'informations ici https://developer.android.com/reference/android/support/v4/app/Fragment.html#isStateSaved ()
la source
cela a fonctionné pour moi ... j'ai découvert cela par moi-même ... j'espère que cela vous aide!
1) NE PAS avoir un FragmentManager / FragmentTransaction "statique" global.
2) onCreate, TOUJOURS initialiser à nouveau le FragmentManager!
échantillon ci-dessous: -
la source
J'obtenais toujours cela lorsque j'essayais de montrer un fragment dans la méthode onActivityForResult (), donc le problème était le suivant:
Ce que j'ai fait est le suivant:
la source
J'ai résolu le problème avec onconfigurationchanged. L'astuce est que, selon le cycle de vie de l'activité Android, lorsque vous avez explicitement appelé une intention (intention de la caméra ou toute autre); l'activité est suspendue et onsavedInstance est appelée dans ce cas. Lors de la rotation de l'appareil dans une position différente de celle pendant laquelle l'activité était active; l'exécution d'opérations de fragment telles que la validation de fragment provoque une exception d'état illégal. Il y a beaucoup de plaintes à ce sujet. Il s'agit de la gestion du cycle de vie des activités Android et des appels de méthode appropriés. Pour le résoudre, j'ai fait ceci: 1-Remplacez la méthode onsavedInstance de votre activité et déterminez l'orientation actuelle de l'écran (portrait ou paysage), puis définissez-y l'orientation de votre écran avant de suspendre votre activité. de cette façon, l'activité vous verrouillez la rotation de l'écran pour votre activité au cas où elle aurait été tournée par une autre. 2-puis, remplacez la méthode d'activité de reprise et définissez maintenant votre mode d'orientation sur capteur afin qu'après l'appel de la méthode enregistrée, il appelle une fois de plus la configuration pour gérer correctement la rotation.
Vous pouvez copier / coller ce code dans votre activité pour y faire face:
la source
J'ai eu le même problème, obtenir IllegalStateException, mais remplacer tous mes appels à commit () par commitAllowingStateLoss () n'a pas aidé.
Le coupable était un appel à DialogFragment.show ().
Je l'entoure de
et ça l'a fait. OK, je ne peux pas afficher la boîte de dialogue, mais dans ce cas, ça allait.
C'était le seul endroit dans mon application où j'ai appelé FragmentManager.beginTransaction () pour la première fois mais je n'ai jamais appelé commit () donc je ne l'ai pas trouvé quand j'ai cherché "commit ()".
Le plus drôle, c'est que l'utilisateur ne quitte jamais l'application. Au lieu de cela, le tueur était une annonce interstitielle AdMob apparaissant.
la source
Ma solution à ce problème était
Dans les méthodes d'ajout de fragments:
Peut être mauvais, mais je n'ai rien trouvé de mieux.
la source
J'ai eu ce problème, mais je pense que ce problème n'est pas lié à commit et commitAllowStateLoss.
Le message de trace et d'exception de pile suivant concerne commit ().
Mais cette exception a été provoquée par onBackPressed ()
Ils ont tous été causés par checkStateLoss ()
mStateSaved sera vrai après onSaveInstanceState.
Ce problème se produit rarement, je n'ai jamais rencontré ce problème, je ne peux pas le reproduire.
J'ai trouvé le problème 25517
Cela pourrait se produire dans les circonstances suivantes
La touche Retour est appelée après onSaveInstanceState, mais avant le démarrage de la nouvelle activité.
utiliser onStop () dans le code
Je ne sais pas quelle est la racine du problème. J'ai donc utilisé une façon laide.
la source
J'ai le même problème dans mon application. J'ai été résolu ce problème en appelant simplement la
super.onBackPressed();
classe précédente et en appelant lacommitAllowingStateLoss()
classe actuelle avec ce fragment.la source
commitAllowingStateLoss()
au lieu decommit()
onSaveInstance sera appelé si un utilisateur fait pivoter l'écran afin de pouvoir charger les ressources associées à la nouvelle orientation.
Il est possible que cet utilisateur ait fait pivoter l'écran, puis en appuyant sur le bouton de retour (car il est également possible que cet utilisateur ait échappé son téléphone en utilisant votre application)
la source
Lisez http://chris-alexander.co.uk/on-engineering/dev/android-fragments-within-fragments/
article. La vérification de fragment.isResumed () m'aide dans onDestroyView sans utiliser la méthode onSaveInstanceState.
la source
Même problème de ma part et après une journée d'analyse de tous les articles, blog et stackoverflow, j'ai trouvé une solution simple. N'utilisez pas du tout saveInstanceState, c'est la condition avec une ligne de code. Sur le code de fragment:
la source
Cela se produit chaque fois que vous essayez de charger un fragment mais que l'activité a changé son état en onPause (). Cela se produit par exemple lorsque vous essayez de récupérer des données et de les charger dans l'activité mais au moment où l'utilisateur a cliqué sur un bouton et a déplacé à l'activité suivante.
Vous pouvez résoudre ce problème de deux manières
Vous pouvez utiliser transaction.commitAllowingStateLoss () au lieu de transaction.commit () pour charger le fragment, mais vous risquez de perdre l'opération de validation effectuée.
ou
Assurez-vous que l'activité est en cours de reprise et ne va pas se mettre en pause lors du chargement d'un fragment. Créez un booléen et vérifiez si l'activité ne va pas à l'état onPause ().
puis pendant le chargement du fragment, vérifiez si l'activité est présente et chargez uniquement lorsque l'activité est au premier plan.
la source
Merci @gunar, mais je pense qu'il y a une meilleure façon.
Selon le doc:
Utilisez donc
commitNow
pour remplacer:la source
Eh bien, après avoir essayé toutes les solutions ci-dessus sans succès (car, fondamentalement, je n'ai pas de transactions).
Dans mon cas, j'utilisais AlertDialogs et ProgressDialog comme fragments qui, parfois, en rotation, lors de la demande de FragmentManager, l'erreur augmente.
J'ai trouvé une solution de contournement mélangeant de nombreux messages similaires:
C'est une solution en 3 étapes, tout est fait sur votre FragmentActivity (dans ce cas, son appelé GenericActivity):
la source
Quand j'utilise startactivity dans un fragment, j'obtiendrai cette exception;
Lorsque je change pour utiliser startactivityforresult, l'exception a disparu :)
Donc, le moyen le plus simple de le résoudre est d'utiliser l'api startActivityForResult :)
la source
J'obtenais cette exception lorsque j'appuyais sur le bouton de retour pour annuler le sélecteur d'intention sur l'activité de mon fragment de carte. J'ai résolu ce problème en remplaçant le code de onResume () (où j'initialisais le fragment et validais la transaction) par onStart () et l'application fonctionne bien maintenant. J'espère que cela aide.
la source
Ceci est corrigé dans Android 4.2 et également dans la source de la bibliothèque de support. [*]
Pour plus de détails sur la cause (et les solutions), reportez-vous au rapport de bogue Google: http://code.google.com/p/android/issues/detail?id=19917
Si vous utilisez la bibliothèque de support, vous ne devriez pas avoir à vous soucier de ce bogue (pour longtemps) [*]. Cependant, si vous utilisez directement l'API (c'est-à-dire que vous n'utilisez pas le FragmentManager de la bibliothèque de support) et que vous ciblez une API sous Android 4.2, vous devrez essayer l'une des solutions.
[*] Au moment d'écrire ces lignes, le gestionnaire de SDK Android distribue toujours une ancienne version qui présente ce bogue.
Éditer Je vais ajouter quelques précisions ici parce que j'ai évidemment confondu d'une manière ou d'une autre celui qui a rejeté cette réponse.
Il existe plusieurs circonstances différentes (mais liées) qui peuvent provoquer la levée de cette exception . Ma réponse ci-dessus se réfère à l'instance spécifique discutée dans la question, c'est-à-dire un bogue dans Android qui a été corrigé par la suite. Si vous obtenez cette exception pour une autre raison, c'est parce que vous ajoutez / supprimez des fragments alors que vous ne devriez pas l'être (après que les états des fragments ont été enregistrés). Si vous êtes dans une telle situation, peut-être que " Fragments imbriqués - IllegalStateException" ne peut pas effectuer cette action après onSaveInstanceState " " peut vous être utile.
la source
Après un peu de recherche, la solution à ce problème est de faire vos validations de fragments dans la reprise.
Source: https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/
la source
Mon cas d'utilisation: j'ai utilisé l'écouteur en fragment pour notifier l'activité que quelque chose s'est passé. J'ai fait un nouveau fragment commit sur la méthode de rappel. Cela fonctionne parfaitement bien la première fois. Mais lors d'un changement d'orientation, l'activité est recréée avec l'état d'instance enregistré. Dans ce cas, le fragment n'est pas créé à nouveau implique que le fragment a l'auditeur qui est une ancienne activité détruite. De toute façon, la méthode de rappel sera déclenchée lors de l'action. Cela va à une activité détruite qui cause le problème. La solution consiste à réinitialiser l'auditeur en fragment avec l'activité en direct actuelle. Cela résout le problème.
la source
Ce que j'ai trouvé, c'est que si une autre application est de type boîte de dialogue et permet d'envoyer des touches à l'application d'arrière-plan, presque toutes les applications d'arrière-plan se bloqueront avec cette erreur. Je pense que nous devons vérifier chaque fois qu'une transaction est effectuée si l'instance a été enregistrée ou restaurée.
la source
Dans mon cas, avec la même exception d'erreur, j'ai mis le "onBackPressed ()" dans un exécutable (vous pouvez utiliser n'importe laquelle de vos vues):
Je ne comprends pas pourquoi, mais ça marche!
la source
Vous appelez peut-être fragmentManager.popBackStackImmediate (); lorsque l'activité est suspendue. L'activité n'est pas terminée mais est suspendue et n'est pas au premier plan. Vous devez vérifier si l'activité est suspendue ou non avant popBackStackImmediate ().
la source
J'ai remarqué quelque chose de très intéressant. J'ai dans mon application la possibilité d'ouvrir la galerie du téléphone et l'appareil demande quelle application utiliser, là je clique sur la zone grise loin de la boîte de dialogue et je vois ce problème. J'ai remarqué comment mon activité passe de onPause, onSaveInstanceState à onResume, il n'arrive pas à visiter onCreateView. Je fais des transactions chez onResume. Donc, ce que j'ai fini par faire, c'est de mettre un indicateur en cours de négation onPause, mais d'être vrai surCreateView. si l'indicateur est vrai onResume alors faites onCommit, sinon commitAllowingStateLoss. Je pourrais continuer et perdre tellement de temps mais je voulais vérifier le cycle de vie. J'ai un appareil qui est sdkversion 23, et je n'ai pas ce problème, mais j'en ai un autre qui est 21, et là je le vois.
la source
vous pouvez utiliser FragmentActivity.onStart avant popBackStackImmediate
comme ça:
http://jorryliu.blogspot.com/2014/09/illegalstateexception-can-not-perform.html
la source