web-dev-qa-db-fra.com

Est-ce la bonne façon de nettoyer la pile de Fragment Back en laissant une pile profondément imbriquée?

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

Dans le volet de sélection de 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 e pour contenir un bouton qui charge un autre fragment e1 également dans le volet de détails. J'ai fait ceci sur la méthode onClick de fragment e 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 e se trouve dans le volet de détails. C'est bien et ce que je veux. Cependant, si je clique sur le bouton back à ce stade, il ne fait rien. Je dois cliquer deux fois parce que e1 est toujours sur la pile. De plus, après avoir cliqué, j'ai obtenu une exception de pointeur null dans onCreateView:

Pour 'résoudre' ce problème, j'ai ajouté le texte suivant chaque fois que A B C D E est sélectionné:

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

Je me demandais simplement si c'était la bonne solution ou si je devais faire quelque chose de différent?

127
PJL

En fonction du comportement souhaité, il existe plusieurs façons de s'y prendre, mais ce lien devrait vous donner toutes les meilleures solutions et, sans surprise, provient 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 de pile arrière initial 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 de la pile arrière et FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) est supposé 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 en POP_BACK_STACK_INCLUSIVE),
248
Joachim

L'autre solution propre si vous ne voulez pas faire apparaître 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. Ainsi, à tout moment, il n'y aura qu'un seul fragment dans la pile.

60
Pawan Maheshwari

Merci à Joachim answer, j'utilise le code pour effacer finalement toutes les entrées de pile.

// 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();

    fm.popBackStack(backStackId, FragmentManager.POP_BACK_STACK_INCLUSIVE);

} /* end of for */
25
Jay Parker

J'ai fait beaucoup de recherches 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 effectue une boucle sur toutes les transactions du backstack et les supprime immédiatement, une à la fois.

Remarque: le code ci-dessus ne fonctionne parfois pas et je fais face à la face ANR à cause de ce code , alors s'il vous plaît, n'essayez pas ceci.

Mettre à jour la méthode ci-dessous supprime tout fregment de ce "nom" de la pile de disques.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • name Si non-null, il s'agit du nom d'un précédent état d'arrière-plan à rechercher; si trouvé, tous les états jusqu'à cet état seront sautés. le
  • L'indicateur POP_BACK_STACK_INCLUSIVE peut être utilisé pour contrôler si l'état nommé lui-même est sauté. Si la valeur est null, seul l'état le plus élevé est affiché.
7
Lokesh

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();
    }
3
Jorge Lozano