web-dev-qa-db-fra.com

FragmentManager exécute déjà des transactions. Quand est-il prudent d'initialiser le pager après le commit?

J'ai une activité hébergeant deux fragments. L'activité commence par montrer un chargeur pendant qu'il charge un objet. L'objet chargé est ensuite passé aux deux fragments en tant qu'arguments via les méthodes newInstance et ces fragments sont attachés.

final FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.replace(R.id.container1, Fragment1.newInstance(loadedObject));
trans.replace(R.id.container2, Fragment2.newInstance(loadedObject));
trans.commit();

Le deuxième fragment contient un fichier Android.support.v4.view.ViewPager et des onglets. onResume on l'initialise comme suit

viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(adapter.getCount()); //the count is always < 4
tabLayout.setupWithViewPager(viewPager);

Le problème est qu'Android jette alors 

Java.lang.IllegalStateException: FragmentManager est déjà en cours d'exécution transactions

Avec cette trace de pile: (j'ai pris Android.support dans les noms de paquets juste pour être bref)

v4.app.FragmentManagerImpl.execSingleAction (FragmentManager.Java:1620) à v4.app.BackStackRecord.commitNowAllowingStateLoss (BackStackRecord.Java:637) à v4.app.FragmentPagerAdapter.finishUpdate (FragmentPagerAdapter.Java:143) sur v4.view.ViewPager.populate (ViewPager.Java:1235) sur v4.view.ViewPager.populate (ViewPager.Java:1083) à v4.view.ViewPager.setOffscreenPageLimit (ViewPager.Java:847)

Les données indiquent si setOffscreenPageLimit(...); est supprimé. Y a-t-il un autre moyen d'éviter ce problème?

Quand dans le cycle de vie la transaction de fragment est-elle terminée afin que je puisse attendre l'installation de mon pageur?

50
Nick Cardoso

Si vous ciblez le SDK 24 ou supérieur, vous pouvez utiliser:

FragmentTransaction.commitNow()

au lieu de commit()

Si vous ciblez d'anciennes versions, essayez d'appeler:

FragmentManager.executePendingTransactions()

après l'appel à commit()

24
marmor

Utilisez simplement childFragmentManger() pour viewpager dans une Fragment

mPagerAdapter = new ScreenSlidePagerAdapter(getChildFragmentManager());
mPager.setAdapter(mPagerAdapter);
123
Hitesh Sahu

J'ai eu cette exception lors du remplacement rapide de 2 fragments ET à l'aide de executePendingTransactions (). Sans appeler cela, il n'y avait pas d'exception.

Quel était mon cas? J'ouvre un fragment A et dans son onResume () (sous une condition) je demande à l'activité de remplacer le fragment par le fragment B. A ce stade, l'exception se produit.

Ma solution consistait à utiliser un Handler.post (exécutable) qui place la requête à la fin de la file d'attente du thread au lieu de l'exécuter immédiatement. De cette façon, nous nous assurons que la nouvelle transaction sera exécutée après la fin des transactions précédentes.

Donc ma solution était aussi simple que:

Handler uiHandler = new Handler();
uiHandler.post(new Runnable()
{
    @Override
    public void run()
    {
        openFragmentB(position);
    }
});
34
M.Paunov

J'ai eu un problème similaire,

Une activité principale ajoutant un fragmentA.

Puis fragmentA une activité principale de rappel pour se remplacer par fragmentB.

MainActivity lève l’exception "fragmentmanager qui exécute déjà la transaction" lors du remplacement et de la validation de la transaction avec fragmentB.

Le problème vient en réalité de fragmentB.

J'ai un TabHost dans le fragment B qui nécessite getfragmentmanager () pour ajouter tabfragment.

Remplacez getfragmentmanager () par getchildfragmentmanager () dans fragmentB, résolvez le problème.

1
Alexandre Levieux

Si quelqu'un utilise Robolectric> 3.6 et au moins jusqu'à la version 4.0.2 avec un ViewPager, cela peut se voir même avec le code correct.

Il existe des informations connexes dans ce problème de github suivi du problème pour Robolectric.

Le problème n’est pas résolu au moment où j’écris cette réponse, et les seules solutions de contournement connues sont d’utiliser @Config (sdk = {27}), qui semble fonctionner pour certains mais ne fonctionne pas pour moi, ou implémenter un ViewPagerShadow avec une solution de contournement dans votre paquet de test avec le code plutôt long référencé sur github (je peux l'inclure ici si c'est mieux mais cela peut ne pas être assez pertinent comme réponse?) et utiliser @Config (shadows = {ShadowViewPager.class})

0
Mike Hardy