Effacer la pile arrière en utilisant des fragments


244

J'ai porté mon application Android sur nid d'abeille et j'ai fait un gros refactor afin d'utiliser des fragments. Dans ma version précédente, lorsque j'appuyais sur le bouton Accueil, je faisais un ACTIVITY_CLEAR_TOPpour réinitialiser la pile arrière.

Maintenant, mon application est juste une seule activité avec plusieurs fragments, donc lorsque j'appuie sur le bouton Accueil, je remplace simplement l'un des fragments à l'intérieur. Comment puis-je vider ma pile arrière sans avoir à utiliser startActivityavec le ACTIVITY_CLEAR_TOPdrapeau?


Évitez d'utiliser des piles de dos! cela n'aide pas vraiment avec l'efficacité globale! utilisez plain replace () ou encore mieux supprimez / ajoutez chaque fois que vous voulez naviguer! Consultez mon message sur stackoverflow.com/questions/5802141/…
stack_ved

Réponses:


430

J'ai posté quelque chose de similaire ici

D'après la réponse de Joachim, de Dianne Hackborn:

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

J'ai fini par utiliser:

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

Mais aurait également pu utiliser quelque chose comme:

((AppCompatActivity)getContext()).getSupportFragmentManager().popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

Ce qui fera apparaître tous les états jusqu'à celui nommé. Vous pouvez alors simplement remplacer le fragment par ce que vous voulez


8
Eh bien, cela équivaut à appuyer sur le bouton de retour une ou plusieurs fois, donc cela change le fragment qui est actuellement visible. (Au moins quand je l'ai essayé)
Peter Ajtai

7
J'ai le même problème que Peter. Je voudrais effacer tous les fragments plutôt que de les parcourir, ce qui a beaucoup d'implications. Par exemple, vous atteindrez des événements de cycle de vie dont vous n'avez pas besoin en sortant chaque fragment de la pile de manière séquentielle.
Brian Griffey

233
Pour aller en haut, utilisez simplement: fragmentManager.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Warpzit

53
Pour ce que ça vaut, en utilisant fragmentManager. popBackStackImmediate (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); a fonctionné encore mieux pour moi car il a empêché les animations des fragments de s'exécuter
roarster

17
Cela ne fonctionne PAS correctement - cela déclenchera un appel à onStart de chaque fragment entre les deux
James

165

Pour répondre au commentaire de @ Warpzit et le rendre plus facile à trouver pour les autres.

Utilisation:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

14
Je crois que l'éclatement de tous les fragments du backstack de cette manière a été rompu dans la dernière bibliothèque v7-appCompat lors de l'utilisation d'AppCompatActivity. Après avoir mis à jour mon application vers la dernière bibliothèque v7-appCompat (21.0.0) et étendu la nouvelle AppCompatActivity, l'éclatement de fragments de la manière ci-dessus laisse quelques fragments dans l'enregistrement de backstack du FragmentManager. Je déconseille de l'utiliser.
dell116

Peut être utiliser popBackStackImmediate.
Kannan_SJD

38

Avec tout le respect dû à toutes les parties concernées; Je suis très surpris de voir combien d’entre vous ont pu effacer la pile complète de fragments avec un simple

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Selon la documentation Android (concernant l' nameargument - le "nul" dans les propositions de travail revendiquées).

Si null, seul l'état supérieur est sauté

Maintenant, je me rends compte que je ne connais pas vos implémentations particulières (comme le nombre d'entrées que vous avez dans la pile arrière à un moment donné), mais je parierais tout mon argent sur la réponse acceptée lorsque vous vous attendez à une définition bien définie comportement sur une plus large gamme d'appareils et de fournisseurs:

(pour référence, quelque chose avec ça)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}

4
pour moi, ce n'était pas le cas puisque chaque pop vous emmène en interne vers la onCreateView de chaque fragment. Où je recevrais un NPE sur une ressource. Mais en utilisant fm.popBackStack (null, FragmentManager.POP_BACK_STACK_INCLUSIVE); a simplement tué tout le backstack.
sud007

1
Avez-vous des idées sur la façon d'ignorer les appels onCreateView lorsque vous utilisez une boucle?
Ayush Goyal

L'effacement du plus haut fragment (null) effacera tous les fragments qui le suivent dans la pile arrière.
2b77bee6-5445-4c77-b1eb-4df3e5

18

Fonctionne pour moi et de manière simple sans utiliser de boucle:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

17

La réponse acceptée ne me suffisait pas. J'ai dû utiliser:

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

2
Cela a été souligné dans une réponse différente, mais juste pour vous assurer qu'il est noté: Si vous placez la pile entière dans une boucle comme celle-ci, vous allez déclencher les méthodes de cycle de vie pour chaque fragment entre le début et la fin de la pile . Il y a de fortes chances que cette implémentation ait des conséquences imprévues, dans la plupart des cas d'utilisation. Il convient également de souligner que popBackStackImmediate()la transaction est synchronisée, ce qui est généralement peu judicieux.
Damien Diehl

16

Backstack clair sans boucles

String name = getSupportFragmentManager().getBackStackEntryAt(0).getName();
getSupportFragmentManager().popBackStack(name, FragmentManager.POP_BACK_STACK_INCLUSIVE);

nom est le paramètre addToBackStack ()

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)

même si vous remplacez la pile .fragment sera vivante mais pas visible
Asthme

8

Je voulais juste ajouter: -

Sauter hors du backstack en utilisant

fragmentManager.popBackStack ()

consiste simplement à supprimer les fragments de la transaction, aucun moyen de supprimer le fragment de l'écran. Donc, idéalement, il peut ne pas être visible pour vous, mais il peut y avoir deux ou trois fragments empilés les uns sur les autres, et sur la touche arrière, l'interface utilisateur peut sembler encombrée, empilée.

Prenons juste un exemple simple: -

Supposons que vous ayez un fragmentA qui charge Fragmnet B à l'aide de fragmentmanager.replace () , puis nous ajoutons AddToBackStack, pour enregistrer cette transaction. Le flux est donc: -

ÉTAPE 1 -> FragmentA-> FragmentB (nous sommes passés à FragmentB, mais le fragment A est en arrière-plan, non visible).

Maintenant, vous travaillez dans fragmentB et appuyez sur le bouton Enregistrer - qui, après l'enregistrement, devrait revenir à fragmentA.

ÉTAPE 2-> Sur sauvegarde de FragmentB, nous revenons à FragmentA.

ÉTAPE 3 -> Une erreur courante serait donc ... dans le Fragment B, nous allons faire fragment Manager.replace () fragmentB avec fragmentA.

Mais ce qui se passe réellement, nous chargeons à nouveau le fragment A, en remplaçant le fragmentB. Il y a donc maintenant deux FragmentA (un de STEP-1 et un de STEP-3).

Deux instances de FragmentsA sont empilées l'une sur l'autre, ce qui n'est peut-être pas visible, mais elle est là.

Donc, même si nous effaçons le backstack par les méthodes ci-dessus, la transaction est effacée mais pas les fragments réels. Donc, idéalement dans un tel cas particulier, en appuyant sur le bouton Enregistrer, vous devez simplement revenir à fragmentA en faisant simplement fm.popBackStack () ou fm.popBackImmediate () .

Donc, corrigez Step3-> fm.popBackStack () pour revenir à fragmentA, qui est déjà en mémoire.


3

En lisant la documentation et en étudiant l'ID du fragment, il semble que ce soit simplement l'index de la pile, donc cela fonctionne:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zéro ( 0) est le bas de la pile, donc le fait d'apparaître inclus efface la pile.

CAVEAT: Bien que ce qui précède fonctionne dans mon programme, j'hésite un peu car la documentation de FragmentManager ne déclare jamais réellement que l'id est l'index de la pile. Il est logique que ce soit le cas, et tous mes journaux de débogage montrent que c'est le cas, mais peut-être que dans certaines circonstances spéciales, ce ne serait pas le cas? Quelqu'un peut-il confirmer cela dans un sens ou dans l'autre? Si c'est le cas, alors ce qui précède est la meilleure solution. Sinon, c'est l'alternative:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }

1
Que diriez-vous d'utiliser fragmentManager..getBackStackEntryAt(0).getId()au lieu de 0? Cela devrait fonctionner même si les identifiants d'entrée de backstack sont à un certain moment différents de l'index de la pile.
ChristophK

3

Utilisez simplement cette méthode et passez la balise Context & Fragment jusqu'à laquelle nous devons supprimer les fragments de backstake.

Usage

clearFragmentByTag(context, FragmentName.class.getName());



public static void clearFragmentByTag(Context context, String tag) {
    try {
        FragmentManager fm = ((AppCompatActivity) context).getSupportFragmentManager();

        for (int i = fm.getBackStackEntryCount() - 1; i >= 0; i--) {
            String backEntry = fm.getBackStackEntryAt(i).getName();
            if (backEntry.equals(tag)) {
                break;
            } else {
                 fm.popBackStack();
            }
        }
    } catch (Exception e) {
        System.out.print("!====Popbackstack error : " + e);
        e.printStackTrace();
    }
}

2

Salut ~ J'ai trouvé une solution bien meilleure, à partir de: https://gist.github.com/ikew0ng/8297033

    /**
 * Remove all entries from the backStack of this fragmentManager.
 *
 * @param fragmentManager the fragmentManager to clear.
 */
private void clearBackStack(FragmentManager fragmentManager) {
    if (fragmentManager.getBackStackEntryCount() > 0) {
        FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);
        fragmentManager.popBackStack(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }
}

2
Veuillez développer votre réponse en expliquant pourquoi cette solution est meilleure.
Simon.SA

Il utilise le mécanisme que le sdk fournit lui-même et ne causera pas de problème npe.
Chenxi

1

Je l'ai fait fonctionner de cette façon:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}

1

Cela fonctionne pour moi, essayez celui-ci:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }

0
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

L'appel à cette méthode serait très soigné.

  1. Aucune boucle requise.
  2. Si vous utilisez l'animation en fragments, elle n'affichera pas trop d'animations. Mais utiliser la boucle le fera.

0
private boolean removeFragFromBackStack() {
    try {
        FragmentManager manager = getSupportFragmentManager();
        List<Fragment> fragsList = manager.getFragments();
        if (fragsList.size() == 0) {
            return true;
        }
        manager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

Merci pour cet extrait de code, qui pourrait fournir une aide limitée et immédiate. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi il s'agit d'une bonne solution au problème et le rendrait plus utile aux futurs lecteurs ayant d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez faites.
Abdelilah El Aissaoui
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.