Clear back stack using fragments
Asked Answered
A

16

279

I ported my Android app to honeycomb and I did a big refactor in order to use fragments. In my previous version, when I pressed the Home button I used to do a ACTIVITY_CLEAR_TOP in order to reset the back stack.

Now my app is just a single Activity with multiple fragments, so when I press the Home button I just replace one of the fragments inside it. How can I clear my back stack without having to use startActivity with the ACTIVITY_CLEAR_TOP flag?

Amytal answered 31/5, 2011 at 10:49 Comment(1)
Avoid using back stacks! it doesn't really help with the overall efficiency! use plain replace() or even better remove/add every time you want to navigate! Check my post on #5802641Nowise
S
471

I posted something similar here

From Joachim's answer, from Dianne Hackborn:

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

I ended up just using:

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

But could equally have used something like:

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

Which will pop all states up to the named one. You can then just replace the fragment with what you want

Seminole answered 1/6, 2011 at 8:5 Comment(13)
But this has huge side effects, doesn't it?Corso
Well, it's equivalent to hitting the back button one or more times, so it changes the fragment that is currently visible. (At least when I've tried it)Corso
I am having the same issue as peter. I'd like to clear all of the fragments out rather than having it cycle through them which has lots of implications. For example, you will hit lifecycle events that you don't need to by popping every fragment off of the stack sequentially.Tips
See the answer by Dianne Hackborn in the Groups link for more ways in which to achieve this.Suribachi
To go to top simply use: fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);Priesthood
For what it's worth, using fragmentManager. popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); worked even better for me as it prevented the fragment animations from executingTansey
Am I the only one that keeps on seing the fragments that are on the stack before reaching the right one? :/ I did try fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); and fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);Pad
@Priesthood 's suggestion worked for me, though in fairness all my animation had the same "left-to-right" motion - I haven't verified behaviour with unusual animations (e.g. dissolve in, top-to-bottom, etc.)Matrilineal
This DOES NOT work properly - it will trigger a call to onStart of every fragment in betweenOrient
As @Orient says, this method works, but all the fragments are replaced until the stack is empty, so every Fragment calls onStart, onCreateView, etc...Outset
This solution doesn't work for me. It returns all fragments, so all layouts are on top of each other. I think this works in previous versions of android.Induline
or it will pop up to root fragment, i.e the fragment added without addToBackStackCortese
popBackStackImmediate will eliminate the starting of every fragment in the stack and will release them all.Killer
G
200

To make an answer for @Warpzit's comment and make it easier for others to find.

Use:

fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Garrott answered 18/10, 2014 at 12:19 Comment(3)
I believe popping all fragments from the backstack this way has been broken in the latest v7-appCompat library when using AppCompatActivity. After updating my app to the lastest v7-appCompat library (21.0.0) and extending the new AppCompatActivity, popping fragments in the above manner is leaving some fragments in the backstack record of the FragmentManager. I'd advise against using this.Sonora
May be use popBackStackImmediate.Saudra
I think this should be the right answer though when i go from frament A to B to C and call this method on C to go back to A this only works once. When i go again from A via B to C and fragmentManager.popBackStackImmediate is triggered, its not navigating me to A again. I use getParentFragmentManager().beginTransaction().replace(x, y).addToBackStack(null).commit(); to navigate from A to B and from B to C. Any idea how to solve my issue?Uralic
F
48

With all due respect to all involved parties; I'm very surprised to see how many of you could clear the entire fragment back stack with a simple

fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

According to Android documentation (regarding the name argument - the "null" in the claimed working proposals).

If null, only the top state is popped

Now, I do realize that I'm lacking knowledge of your particular implementations (like how many entries you have in the back stack at the given point in time), but I would bet all my money on the accepted answer when expecting a well defined behaviour over a wider range of devices and vendors:

(for reference, something along with this)

FragmentManager fm = getFragmentManager(); // or 'getSupportFragmentManager();'
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {    
    fm.popBackStack();
}
Fanfaron answered 4/3, 2015 at 9:1 Comment(5)
for me it was not since each pop takes you internally to the onCreateView of each fragment. Where I would receive a NPE on some resource. But using fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); simply killed all the backstack.Douville
Any insights on how to skip onCreateView calls when popping using loop?Digression
Clearing the top most fragment (null) will clear all fragments that come after it in the back stack.Cipher
The documentation does appear to suggest that only the top fragment will be popped in this case, but the implementation actually does clear the whole backstack when the POP_BACK_STACK_INCLUSIVE flag is used. With POP_BACK_STACK_INCLUSIVE, the logic in FragmentManager.popBackStackState() skips the name==null logic of popping a single entry and goes on to clear all entries. android.googlesource.com/platform/frameworks/base/+/master/core/…Digenesis
@Digenesis Yes, over the years - as surprisingly many developers have suggested a different practical experience than what is stated in the documentation - I too have come to believe that there must be a discrepancy between "the code" and "the book".Fanfaron
P
26

Clear backstack without loops

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

Where name is the addToBackStack() parameter

getSupportFragmentManager().beginTransaction().
                .replace(R.id.container, fragments.get(titleCode))
                .addToBackStack(name)
Pren answered 14/5, 2015 at 9:20 Comment(1)
even if u replace .fragment stack will be alive but not visibleDamnify
C
23

Works for me and easy way without using loop:

 FragmentManager fragmentManager = getSupportFragmentManager();
 //this will clear the back stack and displays no animation on the screen
 fragmentManager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
Carbolize answered 30/7, 2015 at 9:37 Comment(0)
M
18

Accepted answer was not enough for me. I had to use :

FragmentManager fm = getSupportFragmentManager();
int count = fm.getBackStackEntryCount();
for(int i = 0; i < count; ++i) {
    fm.popBackStackImmediate();
}
Martini answered 14/10, 2014 at 12:45 Comment(1)
This was pointed out in a different answer, but just to make sure it's noted: If you pop the whole stack in a loop like this, you're going to trigger the lifecycle methods for every Fragment in between the start and end of the stack. There is a good chance that this implementation would have unintended consequences, in most use cases. It's also worth pointing out that popBackStackImmediate() performs the transaction synchronously, which is, in general, ill-advised.Akeylah
B
14

Hi~I found a solution which is much better,from: 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);
    }
}
Bambino answered 18/10, 2018 at 2:3 Comment(2)
Please expand your answer with why this solution is better.Novitiate
It uses the mechanism that the sdk provides itself,and won't cause some npe issue.Bambino
X
11

I just wanted to add :--

Popping out from backstack using following

fragmentManager.popBackStack()

is just about removing the fragments from the transaction, no way it is going to remove the fragment from the screen. So ideally, it may not be visible to you but there may be two or three fragments stacked over each other, and on back key press the UI may look cluttered,stacked.

Just taking a simple example:-

Suppose you have a fragmentA which loads Fragmnet B using fragmentmanager.replace() and then we do addToBackStack, to save this transaction. So the flow is :--

STEP 1 -> FragmentA->FragmentB (we moved to FragmentB, but Fragment A is in background, not visible).

Now You do some work in fragmentB and press the Save button—which after saving should go back to fragmentA.

STEP 2-> On save of FragmentB, we go back to FragmentA.

STEP 3 ->So common mistake would be... in Fragment B,we will do fragment Manager.replace() fragmentB with fragmentA.

But what actually is happenening, we are loading Fragment A again, replacing FragmentB . So now there are two FragmentA (one from STEP-1, and one from this STEP-3).

Two instances of FragmentsA are stacked over each other, which may not be visible , but it is there.

So even if we do clear the backstack by above methods, the transaction is cleared but not the actual fragments. So ideally in such a particular case, on press of save button you simply need to go back to fragmentA by simply doing fm.popBackStack() or fm.popBackImmediate().

So correct Step3-> fm.popBackStack() go back to fragmentA, which is already in memory.

Xeres answered 31/8, 2015 at 5:16 Comment(0)
E
9

For the kotlin people around here:

repeat(supportFragmentManager.backStackEntryCount) {
    supportFragmentManager.popBackStack()
}
Eunuchoidism answered 6/7, 2021 at 13:14 Comment(0)
F
4

Reading the documentation and studying what the fragment id is, it appears to simply be the stack index, so this works:

fragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);

Zero (0) is the the bottom of the stack, so popping up to it inclusive clears the stack.

CAVEAT: Although the above works in my program, I hesitate a bit because the FragmentManager documentation never actually states that the id is the stack index. It makes sense that it would be, and all my debug logs bare out that it is, but perhaps in some special circumstance it would not? Can any one confirm this one way or the other? If it is, then the above is the best solution. If not, this is the alternative:

while(fragmentManager.getBackStackEntryCount() > 0) { fragmentManager.popBackStackImmediate(); }
Frederique answered 23/7, 2016 at 18:24 Comment(1)
How about using fragmentManager..getBackStackEntryAt(0).getId() instead of 0? This should work even if backstack entry ids are at some point different from the stack index.Inflight
C
4

Just use this method and pass Context & Fragment tag upto which we need to remove the backstake fragments.

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();
    }
}
Chromatics answered 19/8, 2016 at 5:45 Comment(0)
B
4

It is working for me,try this one:

public void clearFragmentBackStack() {
        FragmentManager fm = getSupportFragmentManager();
        for (int i = 0; i < fm.getBackStackEntryCount() - 1; i++) {
            fm.popBackStack();
        }
    }
Balakirev answered 18/1, 2019 at 12:22 Comment(0)
E
1

I got this working this way:

public void showHome() {
    getHandler().post(new Runnable() {
        @Override
        public void run() {
            final FragmentManager fm = getSupportFragmentManager();
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate();
            }
        }
    });
}
Epifaniaepifano answered 28/10, 2014 at 15:11 Comment(0)
L
1
    private void clearBackStack(){
        SupportFragmentManaer fm = getSupportFragmentManager();
        fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

Call to this method would be very neat.

  1. No Loop required.
  2. If you are using animation in fragments, it will not show too many animations. But using loop will.
Label answered 15/2, 2018 at 10:25 Comment(0)
S
1
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;
}
Shorts answered 10/4, 2018 at 12:12 Comment(1)
Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you’ve made.Disturbance
C
1

Kotlin extension

fun AppCompatActivity.clearAllFragments() {
    supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
Ciaracibber answered 24/10, 2023 at 7:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.