Est-ce la bonne façon de nettoyer la pile arrière de fragments lorsque vous quittez une pile profondément imbriquée?

130

J'utilise la bibliothèque de compatibilité Android pour implémenter des fragments et j'ai étendu l'exemple de mise en page afin qu'un fragment contienne un bouton qui déclenche un autre fragment.

Dans le volet de sélection sur la gauche, j'ai 5 éléments sélectionnables - A B C D E.

Chacun charge un fragment (via FragmentTransaction:replace) dans le volet de détails -a b c d e

Maintenant, j'ai étendu le fragment epour contenir un bouton qui charge un autre fragment e1également dans le volet de détails. J'ai fait ceci sur ela méthode onClick de fragment comme suit:

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details_frag, newFrag);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();

Si je fais les sélections suivantes:

E - e - e1 - D - E

Ensuite, le fragment eest dans le volet de détails. C'est bien et ce que je veux. Cependant, si j'appuie sur le backbouton à ce stade, cela ne fait rien. Je dois cliquer dessus deux fois car il e1est toujours sur la pile. De plus, après avoir cliqué, j'ai obtenu une exception de pointeur nul dans onCreateView:

Pour `` résoudre '' ce problème, j'ai ajouté ce qui suit chaque fois que A B C D Eest sélectionné:

FragmentManager fm = getActivity().getSupportFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); ++i) {
    fm.popBackStack();
}

Vous vous demandez simplement si c'est la bonne solution ou si je devrais faire quelque chose de différent?

PJL
la source

Réponses:

252

Eh bien, il existe plusieurs façons de procéder en fonction du comportement prévu, mais ce lien devrait vous donner toutes les meilleures solutions et il n'est pas surprenant qu'il soit de Dianne Hackborn

http://groups.google.com/group/android-developers/browse_thread/thread/d2a5c203dad6ec42

Essentiellement, vous avez les options suivantes

  • Utilisez un nom pour votre état initial de la pile arrière et utilisez FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Utilisez FragmentManager.getBackStackEntryCount()/ getBackStackEntryAt().getId() pour récupérer l'ID de la première entrée sur la pile arrière, et FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) est censé faire apparaître toute la pile arrière ... Je pense que la documentation à ce sujet est tout simplement fausse. (En fait, je suppose que cela ne couvre tout simplement pas le cas où vous passez POP_BACK_STACK_INCLUSIVE),
Joachim
la source
Qu'est-ce que ça veut dire? FragmentManager.getBackStackEntryCount () / getBackStackEntryAt (). GetId ()
dannyroa
4
2ème a travaillé pour moi. Ce que cela signifie pour effacer la pile entière: getSupportFragmentManager (). PopBackStack (getSupportFragmentManager (). GetBackStackEntryAt (0) .getId (), FragmentManager.POP_BACK_STACK_INCLUSIVE);
NickL
@JorgeGarcia est-il possible qu'après popbackstack, nous venons de terminer notre fragment sans redémarrer l'ancien.
duggu
Veuillez noter qu'il existe également la version popBackStackImmediate () puisque popBackStack () est asynchrone, ce qui signifie que le nettoyage ne se produit pas au moment exact où vous appelez la méthode.
Genc du
6
Affirme que le groupe est interdit en tant que spam et que je ne peux pas accéder au lien: (Quelqu'un a-t-il la ressource ailleurs?
EpicPandaForce
61

L'autre solution propre si vous ne voulez pas afficher toutes les entrées de la pile ...

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
getSupportFragmentManager().beginTransaction().replace(R.id.home_activity_container, fragmentInstance).addToBackStack(null).commit();

Cela nettoiera d'abord la pile, puis chargera un nouveau fragment, donc à tout moment, vous n'aurez qu'un seul fragment dans la pile

Pawan Maheshwari
la source
1
Ceci est très mauvais: getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);avant un remplacement () car chargent l'appel Fragment onCreateView(), onActivityCreated()etc. Restauration et Destroing un fragment est instantanément mauvais. Le Fragment peut enregistrer un récepteur par exemple. Cela affecte les performances.
VasileM
@VasileM, pourriez-vous décrire en détails? Dans quels cas c'est mauvais? Est-ce à cause d'un comportement asynchrone de FragmentTransaction? Y a-t-il seulement de mauvaises performances d'une mauvaise pile de fragments?
CoolMind
27

Grâce à la réponse de Joachim , j'utilise le code pour effacer enfin toutes les entrées de la pile arrière.

// In your FragmentActivity use getSupprotFragmentManager() to get the FragmentManager.

// Clear all back stack.
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
for (int i = 0; i < backStackCount; i++) {

    // Get the back stack fragment id.
    int backStackId = getSupportFragmentManager().getBackStackEntryAt(i).getId();

    getSupportFragmentManager().popBackStack(backStackId, 
        FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */
Jay Parker
la source
18
Pourquoi utiliser une boucle ici? Pour moi, FragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE) a effacé toutes les entrées de pile arrière ...
Marek
3
@Marek, car parfois tous les fragments ne doivent pas être supprimés, une boucle convient pour cela.
CoolMind
1
@CoolMind, cela n'a toujours pas de sens pour moi. popBackStack(backStackId, INCLUSIVE)fera remonter tous les fragments (états) à backStackId, donc une fois que vous aurez pop le plus bas ique vous allez pop, tous les plus élevés devraient être sautés en même temps. Alors, à quoi sert une boucle?
LarsH
@LarsH, vous avez raison. Voir stackoverflow.com/a/59158254/2914140 . Afin d'afficher d'autres fragments dans la balise requise, nous devons d'abord ajouter le fragment avec addToBackStack ( tag ).
CoolMind
7

J'ai beaucoup recherché pour nettoyer Backstack, et enfin voir Transaction BackStack et sa gestion . Voici la solution qui a le mieux fonctionné pour moi.

 // CLEAR BACK STACK.
    private void clearBackStack() {
        final FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.getBackStackEntryCount() != 0) {
            fragmentManager.popBackStackImmediate();
        }
    }

La méthode ci-dessus boucle sur toutes les transactions de la backstack et les supprime immédiatement une à la fois.

Remarque: le code ci - dessus ne fonctionne parfois pas et je suis confronté à l' ANR à cause de ce code, alors veuillez ne pas essayer ceci.

La méthode de mise à jour ci-dessous supprime tout le fregment de ce "nom" de la backstack.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • name Si non nul, il s'agit du nom d'un état précédent précédent à rechercher; s'il est trouvé, tous les états jusqu'à cet état seront affichés. le
  • L'indicateur POP_BACK_STACK_INCLUSIVE peut être utilisé pour contrôler si l'état nommé lui-même est popped. Si null, seul l'état supérieur est affiché.
Lokesh
la source
Je ne vois pas pourquoi vous les supprimeriez un à la fois. Y a-t-il une raison pour laquelle vous avez choisi cette solution au lieu des autres solutions? Y a-t-il une raison de les supprimer un à la fois au lieu de tous en même temps?
miva2
Il n'y a pas de méthode pour supprimer la backstack à la fois voir developer.android.com/reference/android/app/...
Lokesh
3

J'utilise un code similaire à ceux qui utilisent la boucle while mais j'appelle le nombre d'entrées dans chaque boucle ... donc je suppose que c'est un peu plus lent

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }
Jorge Lozano
la source
0

Comme écrit dans Comment faire sortir un fragment de backstack et par LarsH ici, nous pouvons afficher plusieurs fragments de haut en bas à une balise spécifique ( avec le fragment étiqueté ) en utilisant cette méthode:

fragmentManager?.popBackStack ("frag", FragmentManager.POP_BACK_STACK_INCLUSIVE);

Remplacez "frag" par la balise de votre fragment. Rappelez-vous que nous devons d'abord ajouter le fragment à backstack avec:

fragmentTransaction.addToBackStack("frag")

Si nous ajoutons des fragments avec addToBackStack(null), nous ne ferons pas apparaître les fragments de cette façon.

CoolMind
la source
-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
farid_z
la source