web-dev-qa-db-fra.com

obtenir une exception "IllegalStateException: impossible d'exécuter cette action après onSaveInstanceState"

J'ai une application Live Android, et du marché, j'ai reçu le suivi de pile suivant et je ne sais pas pourquoi cela se produit car il ne se produit pas dans le code de l'application, mais il est causé par un événement de l'application. (supposition)

Je n'utilise pas Fragments, il existe toujours une référence à FragmentManager. Si un organisme peut apporter des éclaircissements sur 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)  
348
dcool

C'est le bogue le plus stupide que j'ai rencontré jusqu'à présent. J'avais une application Fragment fonctionnant parfaitement pour API <11 , et Force Closing sur API> 11 .

Je ne pouvais vraiment pas comprendre ce qu'ils avaient changé à l'intérieur du cycle de vie Activity dans l'appel à saveInstance, mais voici comment j'ai résolu ceci:

_@Override
protected void onSaveInstanceState(Bundle outState) {
    //No call for super(). Bug on API Level > 11.
}
_

Je ne fais simplement pas l'appel à .super() et tout fonctionne très bien. J'espère que cela vous fera gagner du temps.

MODIFIER: 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 outStateBundle, vous pouvez utiliser les éléments suivants:

_@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putString("WORKAROUND_FOR_BUG_19917_KEY", "WORKAROUND_FOR_BUG_19917_VALUE");
    super.onSaveInstanceState(outState);
}
_

EDIT2: cela peut également se produire si vous essayez d'effectuer une transaction après que votre Activity soit parti en arrière-plan. Pour éviter cela, vous devez utiliser commitAllowingStateLoss()

EDIT3: Les solutions ci-dessus corrigeaient les problèmes rencontrés dans les premières bibliothèques support.v4, à ma connaissance. Mais si vous avez toujours des problèmes avec cela, vous DOIT lisez également le blog de @ AlexLockwood : Fragment Transactions & Loss State Activity

Résumé de l'article de blog (mais je vous recommande fortement de le lire):

  • JAMAIS commit() transactions après onPause() sur pré-Honeycomb et onStop() sur post-Honeycomb
  • Soyez prudent lorsque vous validez des transactions dans les méthodes Activity lifecycle. Utilisation onCreate(), onResumeFragments() et onPostResume()
  • Évitez d'effectuer des transactions à l'intérieur de méthodes de rappel asynchrones
  • Utilisez commitAllowingStateLoss() seulement en dernier recours
447
Ovidiu Latcu

La recherche dans Android du code source sur les causes de ce problème donne à l'indicateur mStateSaved in FragmentManagerImpl la classe (instance disponible dans Activity) a la valeur true. Il est défini sur true lorsque la pile d'arrière-plan est enregistrée (saveAllState) lors d'un appel de Activity#onSaveInstanceState. Ensuite, les appels d'ActivityThread ne réinitialisent pas cet indicateur à l'aide des méthodes de réinitialisation disponibles à partir de FragmentManagerImpl#noteStateNotSaved() et dispatch().

Selon moi, il existe quelques corrections disponibles, en fonction de ce que votre application fait et utilise:

Bonnes manières

Avant toute chose: je ferais de la publicité article d'Alex Lockwood . Ensuite, d'après ce que j'ai fait jusqu'à présent:

  1. Pour les fragments et les activités qui ne nécessitent aucune information d'état, appelez commitAllowStateLoss . Tiré de la documentation:

    Permet l'exécution du commit après l'enregistrement de l'état d'une activité. Ceci est dangereux car la validation peut être perdue si l'activité doit être restaurée ultérieurement de son état. Elle ne doit donc être utilisée que dans les cas où l'état de l'interface utilisateur peut changer de manière inattendue sur l'utilisateur`. J'imagine que c'est bien d'utiliser si le fragment montre des informations en lecture seule. Ou même s'ils affichent des informations modifiables, utilisez les méthodes de rappel pour conserver les informations modifiées.

  2. Juste après la validation de la transaction (vous venez d'appeler commit() ), appelez FragmentManager.executePendingTransactions() .

Manières non recommandées:

  1. Comme Ovidiu Latcu mentionné ci-dessus, n'appelez pas super.onSaveInstanceState(). Mais cela signifie que vous perdrez tout l'état de votre activité et l'état des fragments.

  2. Remplacez onBackPressed et appelez-y uniquement finish(). Cela devrait être OK si votre application n'utilise pas l'API Fragments; comme dans super.onBackPressed, il existe un appel à FragmentManager#popBackStackImmediate().

  3. Si vous utilisez à la fois l'API Fragments et que l'état de votre activité est important/vital, vous pouvez alors appeler à l'aide de l'API de réflexion FragmentManagerImpl#noteStateNotSaved(). Mais c'est un bidouillage, ou on pourrait dire que c'est une solution de contournement. Je ne l’aime pas, mais dans mon cas, c’est tout à fait acceptable, car j’ai le code d’une application existante qui utilise un code obsolète (TabActivity et implicitement LocalActivityManager).

Voici le code qui utilise la réflexion:

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    invokeFragmentManagerNoteStateNotSaved();
}

@SuppressWarnings({ "rawtypes", "unchecked" })
private void invokeFragmentManagerNoteStateNotSaved() {
    /**
     * For post-Honeycomb devices
     */
    if (Build.VERSION.SDK_INT < 11) {
        return;
    }
    try {
        Class cls = getClass();
        do {
            cls = cls.getSuperclass();
        } while (!"Activity".equals(cls.getSimpleName()));
        Field fragmentMgrField = cls.getDeclaredField("mFragments");
        fragmentMgrField.setAccessible(true);

        Object fragmentMgr = fragmentMgrField.get(this);
        cls = fragmentMgr.getClass();

        Method noteStateNotSavedMethod = cls.getDeclaredMethod("noteStateNotSaved", new Class[] {});
        noteStateNotSavedMethod.invoke(fragmentMgr, new Object[] {});
        Log.d("DLOutState", "Successful call for noteStateNotSaved!!!");
    } catch (Exception ex) {
        Log.e("DLOutState", "Exception on worka FM.noteStateNotSaved", ex);
    }
}

À votre santé!

75
gunar

Une telle exception se produira si vous essayez d'effectuer une transition de fragment après l'appel de onSaveInstanceState() de votre activité de fragment.

Cela peut arriver si vous laissez une AsyncTask (ou Thread) en cours d'exécution lorsqu'une activité est arrêtée.

Toute transition après l'appel de onSaveInstanceState() peut éventuellement être perdue si le système récupère l'activité des ressources et la recrée ultérieurement.

34
FunkTheMonk

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!

27
MJ.Ahmadi

Cela peut également se produire lorsque vous appelez dismiss() sur un fragment de boîte de dialogue une fois que l'écran a été verrouillé\vide et que l'état de l'instance de la boîte de dialogue Activité + a été enregistré. Pour contourner cet appel:

dismissAllowingStateLoss()

Littéralement, chaque fois que je rejette un dialogue, je ne me soucie plus de son état de toute façon, alors c'est correct, vous ne perdez aucun état.

18
Brian Dilley

Solution courte et efficace:

Suivez les étapes simples:

Étape 1: Remplacez l'état onSaveInstanceState dans le fragment respectif. Et enlevez la super méthode.

@Override
public void onSaveInstanceState(Bundle outState) {
};

Étape 2: Utilisez CommitAllowingStateLoss (); au lieu de commit (); tandis que les opérations de fragment.

fragmentTransaction.commitAllowingStateLoss();
17
Basbous

Je pense que l’état du cycle de vie peut aider à prévenir un tel crash à partir de Android support lib v26.1.0, vous pouvez effectuer la vérification suivante:

if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)){
  // Do fragment's transaction commit
}

ou vous pouvez essayer:

Fragment.isStateSaved()

plus d'informations ici https://developer.Android.com/reference/Android/support/v4/app/Fragment.html#isStateSaved ()

12
Jamal

cela a fonctionné pour moi ... je l'ai découvert par moi-même ... j'espère que cela vous aidera!

1) NE PAS avoir de FragmentManager/FragmentTransaction "statique" global.

2) onCreate, TOUJOURS initialiser à nouveau FragmentManager!

échantillon ci-dessous: -

public abstract class FragmentController extends AnotherActivity{
protected FragmentManager fragmentManager;
protected FragmentTransaction fragmentTransaction;
protected Bundle mSavedInstanceState;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedInstanceState = savedInstanceState;
    setDefaultFragments();
}

protected void setDefaultFragments() {
    fragmentManager = getSupportFragmentManager();
    //check if on orientation change.. do not re-add fragments!
    if(mSavedInstanceState == null) {
        //instantiate the fragment manager

        fragmentTransaction = fragmentManager.beginTransaction();

        //the navigation fragments
        NavigationFragment navFrag = new NavigationFragment();
        ToolbarFragment toolFrag = new ToolbarFragment();

        fragmentTransaction.add(R.id.NavLayout, navFrag, "NavFrag");
        fragmentTransaction.add(R.id.ToolbarLayout, toolFrag, "ToolFrag");
        fragmentTransaction.commitAllowingStateLoss();

        //add own fragment to the nav (abstract method)
        setOwnFragment();
    }
}
7
kurayami88

J'obtenais toujours cela quand j'essayais de montrer un fragment dans la méthode onActivityForResult (), alors le problème était le suivant:

  1. Mon activité est suspendue et arrêtée, ce qui signifie que onSaveInstanceState () a déjà été appelé (pour les dispositifs antérieurs à Honeycomb et postérieurs à Honeycomb).
  2. En cas de résultat, j'ai effectué une transaction pour afficher/masquer un fragment, ce qui provoque cette exception IllegalStateException.

Ce que j'ai fait est ensuite:

  1. Valeur ajoutée pour déterminer si l’action souhaitée a été effectuée (par exemple, prendre une photo à partir d’un camere - isPhotoTaken) - il peut s’agir d’une valeur booléenne ou entière, selon le nombre de transactions dont vous avez besoin.
  2. Dans la méthode onResumeFragments () overriden, j'ai vérifié ma valeur et, après avoir effectué les transactions de fragments dont j'avais besoin. Dans ce cas, commit () n'a pas été exécuté après onSaveInstanceState, car l'état a été renvoyé dans la méthode onResumeFragments ().
6
Array

J'ai résolu le problème avec onconfigurationchanged. Le truc, c'est que, selon Android cycle de vie de l'activité, lorsque vous appelez explicitement 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 vers une position différente de celle pendant laquelle l'activité était active; faire des opérations de fragment telles que fragment commit provoque une exception d'état illégale. Il y a beaucoup de plaintes à ce sujet. Il s’agit de Android gestion du cycle de vie des activités et des appels de méthode appropriés. Pour résoudre ce problème, j'ai procédé comme suit: 1-Remplacez la méthode onsavedInstance de votre activité et déterminez l'orientation actuelle de l'écran (portrait ou paysage), puis définissez l'orientation de votre écran sur cette activité avant la pause de votre activité. De cette façon, vous verrouillez la rotation de l'écran pour votre activité si elle a déjà été pivotée. Ensuite, remplacez la méthode d’activité de reprise et définissez votre mode d’orientation sur sensor afin qu’après l’appel de la méthode onsaved, elle appelle une nouvelle fois la configuration pour traiter correctement la rotation.

Vous pouvez copier/coller ce code dans votre activité pour le gérer:

@Override
protected void onSaveInstanceState(Bundle outState) {       
    super.onSaveInstanceState(outState);

    Toast.makeText(this, "Activity OnResume(): Lock Screen Orientation ", Toast.LENGTH_LONG).show();
    int orientation =this.getDisplayOrientation();
    //Lock the screen orientation to the current display orientation : Landscape or Potrait
    this.setRequestedOrientation(orientation);
}

//A method found in stackOverflow, don't remember the author, to determine the right screen orientation independently of the phone or tablet device 
public int getDisplayOrientation() {
    Display getOrient = getWindowManager().getDefaultDisplay();

    int orientation = getOrient.getOrientation();

    // Sometimes you may get undefined orientation Value is 0
    // simple logic solves the problem compare the screen
    // X,Y Co-ordinates and determine the Orientation in such cases
    if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        Configuration config = getResources().getConfiguration();
        orientation = config.orientation;

        if (orientation == Configuration.ORIENTATION_UNDEFINED) {
        // if height and widht of screen are equal then
        // it is square orientation
            if (getOrient.getWidth() == getOrient.getHeight()) {
                orientation = Configuration.ORIENTATION_SQUARE;
            } else { //if widht is less than height than it is portrait
                if (getOrient.getWidth() < getOrient.getHeight()) {
                    orientation = Configuration.ORIENTATION_PORTRAIT;
                } else { // if it is not any of the above it will defineitly be landscape
                    orientation = Configuration.ORIENTATION_LANDSCAPE;
                }
            }
        }
    }
    return orientation; // return value 1 is portrait and 2 is Landscape Mode
}

@Override
public void onResume() {
    super.onResume();
    Toast.makeText(this, "Activity OnResume(): Unlock Screen Orientation ", Toast.LENGTH_LONG).show();
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
} 
5
douggynix

J'ai le même problème dans mon application. J'ai résolu ce problème en appelant simplement la super.onBackPressed(); de la classe précédente et en appelant la commitAllowingStateLoss() de la classe en cours avec ce fragment.

4
Peter

J'ai ce problème.Mais je pense que ce problème n'est pas lié à commit et commitAllowStateLoss.

La trace de pile et le message d'exception suivants concernent commit ().

Java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at Android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.Java:1341)
at Android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.Java:1352)
at Android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.Java:595)
at Android.support.v4.app.BackStackRecord.commit(BackStackRecord.Java:574)

Mais cette exception a été causée par onBackPressed ()

Java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at Android.support.v4.app.FragmentManagerImpl.checkStateLoss(Unknown Source)
at Android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(Unknown Source)
at Android.support.v4.app.FragmentActivity.onBackPressed(Unknown Source)

Ils ont tous été causés par checkStateLoss ()

private void checkStateLoss() {
    if (mStateSaved) {
        throw new IllegalStateException(
                "Can not perform this action after onSaveInstanceState");
    }
    if (mNoTransactionsBecause != null) {
        throw new IllegalStateException(
                "Can not perform this action inside of " + mNoTransactionsBecause);
    }

mStateSaved sera vrai après onSaveInstanceState.

Ce problème se produit rarement.J'ai jamais rencontré ce problème.Je ne peux pas répéter le problème.

J'ai trouvé numéro 25517

Cela aurait pu se produire dans les circonstances suivantes

  1. La touche Précédent est appelée après onSaveInstanceState, mais avant le démarrage de la nouvelle activité.

  2. tilisez onStop () dans le code

Je ne sais pas quelle est la racine du problème. Donc j'ai utilisé une manière laide.

@Override
public void onBackPressed() {

    try{
        super.onBackPressed();
    }catch (IllegalStateException e){
        // can output some information here
        finish();
    }
}
4
oO_ox

Ma solution à ce problème était

Dans fragment, ajoutez des méthodes:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    ...
    guideMapFragment = (SupportMapFragment)a.getSupportFragmentManager().findFragmentById(R.id.guideMap);
    guideMap = guideMapFragment.getMap();
    ...
}

@Override
public void onDestroyView() {
    SherlockFragmentActivity a = getSherlockActivity();
    if (a != null && guideMapFragment != null) {
        try {
            Log.i(LOGTAG, "Removing map fragment");
            a.getSupportFragmentManager().beginTransaction().remove(guideMapFragment).commit();
            guideMapFragment = null;
        } catch(IllegalStateException e) {
            Log.i(LOGTAG, "IllegalStateException on exit");
        }
    }
    super.onDestroyView();
}

Peut-être mauvais, mais n'a rien trouvé de mieux.

4
mc.dev

J'ai eu le même problème, obtenant IllegalStateException, mais le remplacement de tous mes appels à commit () par commitAllowingStateLoss () n'a pas aidé.

Le coupable était un appel à DialogFragment.show ().

Je l'entoure de

try {
    dialog.show(transaction, "blah blah");
}
catch(IllegalStateException e) {
    return;
}

et cela l'a fait. OK, je ne parviens pas à afficher la boîte de dialogue, mais dans ce cas, tout allait bien.

C’était le seul endroit de mon application où j’appelais pour la première fois FragmentManager.beginTransaction () mais n’appelais jamais commit (), je ne l’ai donc pas trouvé quand j’ai cherché "commit ()".

La chose amusante est que l'utilisateur ne quitte jamais l'application. Au lieu de cela, le tueur était une annonce interstitielle AdMob.

4

onSaveInstance sera appelée si un utilisateur fait pivoter l'écran pour qu'il puisse charger les ressources associées à la nouvelle orientation.

Il est possible que cet utilisateur ait fait pivoter l'écran, puis ait appuyé sur le bouton Précédent (car il est également possible que cet utilisateur ait égaré son téléphone lors de l'utilisation de votre application).

3
dols

Lire http://chris-alexander.co.uk/on-engineering/dev/Android-fragments-within-fragments/

article. La vérification fragment.isResumed () m'aide à utiliser onDestroyView sans utiliser la méthode onSaveInstanceState.

2
andep

Cela se produit chaque fois que vous essayez de charger un fragment mais que l'activité a changé d'état en onPause (). Cela se produit par exemple lorsque vous essayez d'extraire des données et de les charger dans l'activité, mais au moment où l'utilisateur a cliqué sur un bouton et 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 fragment, mais vous risquez de perdre la validation de l'opération de validation effectuée.

ou

Assurez-vous que l'activité est en cours de reprise et qu'elle ne passe pas en état de pause lors du chargement d'un fragment. Créez un booléen et vérifiez si l'activité ne passe pas à l'état onPause ().

@Override
public void onResume() {
    super.onResume();
    mIsResumed = true;
}

@Override
public void onPause() {
    mIsResumed = false;
    super.onPause();
}

puis, lors du chargement de fragments, vérifiez si l’activité est présente et chargez-la uniquement lorsque l’activité est au premier plan.

if(mIsResumed){
 //load the fragment
}
2
sharath kumar

Même problème 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 SavedInstanceState, c'est la condition avec une ligne de code. Sur le code de fragment:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(null);
    .....
2
Tobia Caneschi

Merci @gunar, mais je pense qu'il existe un meilleur moyen.

Selon le doc:

 * If you are committing a single transaction that does not modify the
 * fragment back stack, strongly consider using
 * {@link FragmentTransaction#commitNow()} instead. This can help avoid
 * unwanted side effects when other code in your app has pending committed
 * transactions that expect different timing.
 *
 * @return Returns true if there were any pending transactions to be
 * executed.
 */
public abstract boolean executePendingTransactions();

Utilisez donc commitNow pour remplacer:

fragmentTransaction.commit();
FragmentManager.executePendingTransactions()
0
JianxinLi

Je recevais cette exception lorsque j'appuyais sur le bouton de retour pour annuler le sélecteur d'intention de l'activité de mon fragment de carte. J'ai résolu ce problème en remplaçant le code de onResume () (où j'étais en train d'initialiser le fragment et de valider la transaction) sur onStart () et l'application fonctionne correctement maintenant. J'espère que ça aide.

0
DCS

J'ai remarqué quelque chose de très intéressant. J'ai dans mon application l'option d'ouvrir la galerie du téléphone et le périphérique demande quelle application utiliser, là je clique sur la zone grise en dehors de la boîte de dialogue et j'ai vu ce problème. J'ai remarqué comment mon activité se passe de onPause, onSaveInstanceState à onResume, il n'est pas arrivé de visiter onCreateView. Je fais des transactions chez onResume. Donc, ce que j'ai fini par faire est de définir un indicateur qui est annulé surPause, mais qui vaut true surCreateView. si l'indicateur est vrai sur onResume, faites onCommit, sinon commitAllowingStateLoss. Je pouvais continuer et perdre beaucoup de temps, mais je voulais vérifier le cycle de vie. J'ai un appareil qui est sdkversion 23, et je ne comprends pas ce problème, mais j'en ai un autre qui est 21, et là je le vois.

0
Juan Mendez

Lorsque j'utilise startactivity dans un fragment, j'obtiens cette exception;

Quand je change pour utiliser startactivityforresult, l'exception a disparu :)

Le moyen le plus simple de résoudre ce problème consiste à utiliser l’API startActivityForResult :)

0
Question

Mon cas d'utilisation: J'ai utilisé listener in fragment pour informer l'activité que quelque chose s'était passé. J'ai fait nouveau fragment commit sur la méthode de rappel. Cela fonctionne parfaitement bien la première fois. Mais lors du changement d'orientation, l'activité est recréée avec l'état d'instance enregistré. Dans ce cas, le fragment non créé à nouveau implique que le fragment possède l'auditeur, ce qui constitue une activité détruite ancienne. Peu importe la méthode de rappel, l'action sera déclenchée. Cela entraîne 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.

0
Ganesh Kanna

Après avoir recherché un peu, la solution à ce problème est de faire vos commits de fragments dans le résumé.

Source: https://wenchaojames.wordpress.com/2013/01/12/illegalstateexception-from-onactivityresult/

0
jai

Ce que j’ai trouvé, c’est que si une autre application est du type dialogue et permet l’envoi de contacts à l’application d’arrière-plan, presque toutes les applications d’arrière-plan planteront avec cette erreur. Je pense que nous devons vérifier chaque fois qu'une transaction est effectuée si l'instance a été sauvegardée ou restaurée.

0
chris

Dans mon cas, avec la même exception d'erreur, j'ai mis "onBackPressed ()" dans un exécutable (vous pouvez utiliser n'importe lequel de vos points de vue):

myView.post(new Runnable() {
                    @Override
                    public void run() {
                        onBackPressed()
                    }
                });

Je ne comprends pas pourquoi, mais ça marche!

0
Alecs

Vous appelez peut-être fragmentManager.popBackStackImmediate (); quand l'activité est en pause. L'activité n'est pas terminée mais est en pause et pas au premier plan. Vous devez vérifier si l'activité est en pause ou non avant popBackStackImmediate ().

0
Murat

Ceci est corrigé dans Android 4.2 et également dans le source de la bibliothèque de support. [*]

Pour plus de détails sur la cause (et les solutions de rechange), 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 (pendant longtemps) [*]. Toutefois, si vous utilisez directement l'API (c'est-à-dire que vous n'utilisez pas FragmentManager de la bibliothèque de support) et ciblez une API sous Android 4.2, vous devrez essayer l'une des solutions de contournement.

[*] Au moment de la rédaction, Android SDK Manager distribuait toujours une ancienne version présentant ce bogue.

Modifier Je vais ajouter quelques précisions ici, car j'ai évidemment confondu quiconque a voté contre 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 fait référence à l'instance spécifique décrite dans la question, à savoir 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é sauvegardés). Si vous êtes dans une telle situation, alors " Fragments imbriqués - IllegalStateException" Impossible d'effectuer cette action après onSaveInstanceState " " peut vous être utile.

0
Benjamin Dobell

Eh bien, après avoir essayé toutes les solutions ci-dessus sans succès (parce que fondamentalement, je n’ai pas de transactions).

Dans mon cas, j’utilisais AlertDialogs et ProgressDialog en tant que fragments qui, parfois, en rotation, lorsqu’on demandait FragmentManager, l’erreur montait.

J'ai trouvé une solution de contournement combinant plusieurs messages similaires:

C'est une solution en 3 étapes, toutes effectuées sur votre FragmentActivity (dans ce cas, elle s'appelle GenericActivity):

private static WeakReference<GenericActivity> activity = null; //To avoid bug for fragments: Step 1 of 3

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    //To avoid bug for fragments: Step 2 of 3
    activity = new WeakReference<GenericActivity>(this);
}

@Override
public FragmentManager getSupportFragmentManager(){
    //To avoid bug for fragments: Step 3 of 3
    if (this == activity.get()) {
        return super.getSupportFragmentManager();
    }
    return activity.get().getSupportFragmentManager();
}
0
Antilope