web-dev-qa-db-fra.com

Gestion de backstack: le redémarrage doit être créé uniquement pendant la phase d'initialisation du propriétaire

J'utilise une barre de navigation inférieure dans mon MainActivity pour gérer certains fragments. C'est le code utilisé pour basculer entre eux:

private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
    if (item.isChecked &&
        supportFragmentManager.findFragmentById(R.id.act_main_fragment_container) != null
    )
        return@OnNavigationItemSelectedListener false
    val fragment =
        when (item.itemId) {
            R.id.navigation_home      -> fragments[0]
            R.id.navigation_bookings  -> fragments[1]
            R.id.navigation_messages  -> fragments[2]
            R.id.navigation_dashboard -> fragments[3]
            R.id.navigation_profile   -> fragments[4]
            else                      -> fragments[0]
        }
    this replaceWithNoBackStack fragment
    return@OnNavigationItemSelectedListener true
}

la méthode replaceWithNoBackstack n'est qu'un raccourci pour cela:

supportFragmentManager
    ?.beginTransaction()
    ?.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
    ?.replace(containerId, fragment)
    ?.commit()

Le problème est que lorsque je bascule plus rapidement entre eux, mon application se bloque à l'exception suivante:

Java.lang.IllegalStateException: le redémarrage doit être créé uniquement pendant la phase d'initialisation du propriétaire sur androidx.savedstate.SavedStateRegistryController.performRestore (SavedStateRegistryController.Java:59) sur androidx.fragment.app.Fragment.performCreate (Fragment.Java:2580) fragment.app.FragmentManagerImpl.moveToState (FragmentManagerImpl.Java:837) sur androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState (FragmentManagerImpl.Java:1237) sur androidx.fragment.app.FragmentManagerImpl.moveTartManagerImplava2 .fragment.app.BackStackRecord.executeOps (BackStackRecord.Java:439) sur androidx.fragment.app.FragmentManagerImpl.executeOps (FragmentManagerImpl.Java:2075) sur androidx.fragment.app.FragmentManagerImpl.executeOpsTog65Imag (FragmentManager) androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute (FragmentManagerImpl.Java:1820) sur androidx.fragment.app.FragmentManagerImpl.execPendingActions (FragmentMana gerImpl.Java:1726) sur androidx.fragment.app.FragmentManagerImpl $ 2.run (FragmentManagerImpl.Java:150) sur Android.os.Handler.handleCallback (Handler.Java:789) sur Android.os.Handler.dispatchMessage (Handler. Java: 98) sur Android.os.Looper.loop (Looper.Java:164) sur Android.app.ActivityThread.main (ActivityThread.Java:6709) sur Java.lang.reflect.Method.invoke (Native Method) sur com .Android.internal.os.Zygote $ MethodAndArgsCaller.run (Zygote.Java:240) sur com.Android.internal.os.ZygoteInit.main (ZygoteInit.Java:769) J'ai beaucoup cherché et je n'ai pas trouvé une réponse.

J'ai également cette erreur si je fais un appel API, place l'application en arrière-plan, attend la réponse et au moment où je reviens à l'application, l'application se bloque car j'essaie d'afficher un fragment de dialogue immédiatement (la raison Je pense que cela se produit est que la transaction de recréation du fragment en revenant de l'arrière-plan est toujours en cours au moment d'afficher le fragment de dialogue). J'ai résolu cela de manière hacky en définissant un délai de 500 ms pour la boîte de dialogue car je ne pouvais pas trouver d'autres solutions.

Veuillez demander si vous avez besoin de plus de détails à ce sujet. Merci d'avance!

SOLUTIONS TEMP POSSIBLES

EDIT J'ai résolu ce problème en rétrogradant la compatibilité de l'application à androidx.appcompat:appcompat:1.0.2 mais ce n'est qu'une solution temporaire, car je devrai la mettre à jour à l'avenir. J'espère que quelqu'un le découvrira.

EDIT 2 J'ai résolu le problème en supprimant setTransition () des transactions de fragments. Au moins, je connais la raison pour laquelle Android n'ont pas de bonnes transitions en général

EDIT Peut-être que la meilleure solution pour éviter ce problème et faire fonctionner les choses en douceur est simplement d'utiliser ViewPager pour gérer la navigation dans la barre inférieure

19
Gabi

Rien ne fonctionnait sauf la solution de Drown Coder , mais elle n'était toujours pas parfaite, car elle ajoute des transactions au backstack. Donc, si vous appuyez sur tous les boutons dans la navigation inférieure, vous avez au moins 1 de chaque fragment en backstack. J'ai légèrement amélioré cette solution, donc vous n'utilisez pas .replace() qui plante l'application avec des animations de type action.

Voici le code:

if (getChildFragmentManager().getBackStackEntryCount() > 0) {
    getChildFragmentManager().popBackStack();
}

FragmentTransaction addTransaction = getChildFragmentManager().beginTransaction();
addTransaction.setCustomAnimations(R.animator.fragment_fade_in, R.animator.fragment_fade_out);
addTransaction.addToBackStack(null);
addTransaction.add(R.id.frame, fragment, fragment.getClass().getName()).commitAllowingStateLoss();
0
Dmitriy Pavlukhin

J'ai ce problème lors de l'utilisation de setCustomAnimations. en supprimant setCustomAnimations a résolu mon problème. aussi je n'ai aucun problème lorsque je crée une nouvelle instance de fragment avant de le montrer même en utilisant setCustomAnimation.

EDIT: une autre façon consiste à ajouter un fragment au backstack.

0
Hadi Ahmadi