web-dev-qa-db-fra.com

FragmentStatePagerAdapter IllegalStateException: <MyFragment> n'est pas actuellement dans le FragmentManager.

Je reçois cela dans certains cas, dans onResume (), d'une activité qui utilise un FragmentStatePagerAdapter. Lors de l'utilisation du bouton de retour de l'appareil. Pas toujours. Non reproduisible.

J'utilise le package de support v4, dernière révision (8).

Déjà recherché avec google, pas de succès pour trouver une réponse utile.

En regardant dans la source, il est jeté ici: FragmentManager.Java

@Override
public void putFragment(Bundle bundle, String key, Fragment fragment) {
    if (fragment.mIndex < 0) {
        throw new IllegalStateException("Fragment " + fragment
                + " is not currently in the FragmentManager");
    }
    bundle.putInt(key, fragment.mIndex);
}

Mais pourquoi l’index du fragment <0 est-il là?

Le code instanciant les fragments:

@Override
public Fragment getItem(int position) {
    Fragment fragment = null;

    switch(position) {
        case 0:
            fragment = MyFragment.newInstance(param1);
            break;
        case 1:
            fragment = MyFragment2.newInstance(param2, param3);
            break;
    }
    return fragment;
}

@Override
public int getCount() {
    return 2;
}

Je ne peux pas non plus déboguer par le code source, car le package de support ne me permet pas de joindre le code source, pour une raison quelconque ...

28
Ixx

Compris, la raison en était que je lance l’adaptateur chaque fois dans onResume ().

Si j'instancie l'adaptateur une seule fois dans le cycle de vie de l'activité, cela ne se produit plus.

5
Ixx

Si votre ViewPager est mis en page à l'intérieur d'un fragment (et non d'une activité):

mViewPager.setAdapter (new MyFragmentStatePagerAdapter (getEnfantFragmentManager ()));

15
Thomas G.

J'ai eu la même erreur ici, mais pour une autre raison.

Dans mon cas, j'avais getItemPosition de remplacement dans mon FragmentStatePagerAdapter. Mon idée était de renvoyer la position, si l'élément existe, ou un POSITION_NONE, s'il n'existe plus.

Eh bien, mon problème était le fait que lorsque ma collection était vide, je renvoyais POSITION_NONE. Et cela a tout cassé.

Mon correctif était de retourner POSITION_UNCHANGED quand j'avais une collection vide.

J'espère que ça aide quelqu'un d'autre.

10
laggedHero

Les deux éléments clés pour comprendre le bogue sont:

  1. Cela arrive parfois.
  2. Cela se passe dans onResume()

Compte tenu de ces informations, il est probable que ViewPager ne conserve pas l’état de vos Fragments. Si vous manipulez les Fragment directement à partir de Activity, il est possible que Fragment hors page soit détruit et que votre Activity tente de manipuler un fragment null. Pour conserver l’état de Fragment même s’il ne se trouve pas dans l’écran actuel, le correctif est assez simple:

private static final int NUM_ITEMS = 2;

ViewPager mPager = /** instantiate viewpager **/;
mPager.setOffscreenPageLimit(NUM_ITEMS-1);

Vous pouvez lire à ce sujet ici: 

ViewPager Des fragments sont détruits au fil du temps?

8
Alex Lockwood

Cette exception signifie que vous essayez de joindre un fragment à une activité dont l'état n'est plus correct pour attacher les fragments. Ce que cela signifie, c’est que, chaque fois que nous essayons d’attacher des fragments ( notamment via un appel asynchrone ), il existe une faible probabilité que quelqu'un ait appuyé sur le bouton Précédent et que l’activité est en train de se détruire lors de la connexion du fragment. Ce n'est pas toujours reproductible car c'est juste une condition de concurrence critique, et peut ne pas toujours se produire.

Il y a deux façons de résoudre ce problème:

1) Cela se produit lorsque le statut onSaveInstanceState de votre activité a été appelé et que vous tentez de joindre le fragment, car Android ne pourra pas enregistrer l'état de votre fragment maintenant, une exception sera alors générée. Pour résoudre ce problème et si vous ne sauvegardez pas l'état de votre fragment, essayez d'utiliser

commitAllowingStateLoss () , tout en validant la transaction.

2) Pour plus de sécurité, vérifiez si votre activité est dans un état correct ou non avant de joindre le fragment, utilisez le code suivant dans onPause:

    boolean isInCorrectState;

    public void onCreate{
    super.onCreate();
    isInCorrectState = true;
    }

    public void onPause() {
    super.onPause();
      if(isFinishing()){
        isInCorrectState = false;
       }
    }

Utilisez maintenant cet indicateur pour vérifier si votre activité est dans un état correct ou non avant de joindre le fragment. Signification attacher le fragment iff isInCorrectState == true .

4
Vivek Soneja

Pour moi, la raison était autre chose.

Dans ma Loader.onLoaderReset(), j'ai effacé les données de l'adaptateur. Lorsque je quittais l'application, onDestroy () a réinitialisé le chargeur, ce qui a effacé la variable FragmentStatePagerAdapter. Je pense que l'adaptateur a effacé toutes les références à ses fragments, mais d'une manière ou d'une autre, le FragmentManager n'a pas remarqué et a lancé l'exception. Cela ne me semble pas très logique.

Notez que pour moi c'est arrivé Activity.onDestroy().

J'espère que ça aide quelqu'un.

2
Michał K

Les fragments dans ViewPager sont corrigés. Au lieu d'essayer de remplacer les fragments de l'adaptateur, essayez de donner un ensemble de fragments différent et notifyDataSet modifié, ou profitez de FrameLayout pour afficher un autre fragment par-dessus le fragment actuel de l'onglet Vue.

Il y a ma solution qui fonctionne:

Le geste de glissement appliqué au niveau de fragment avec ViewPager avec son glissement par défaut désactivé

0
Abhinav Saxena