134

I'm using the Android Compatibility library to implement fragments and have extended the layout sample so that a fragment contains a button which fires off another fragment.

In the selection pane on the left I have 5 selectable items - A B C D E.

Each loads up a fragment (via FragmentTransaction:replace) in the details pane - a b c d e

Now I've extended fragment e to contain a button which loads up another fragment e1 also in the details pane. I've done this on fragment e's onClick method as follows:

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

If I make the following selections:

E - e - e1 - D - E

Then fragment e is in the details pane. This is fine and what I want. However, if I hit the back button at this point it does nothing. I have to click it twice because e1 is still on the stack. Furthermore after clicking around I got a null pointer exception in onCreateView:

To 'solve' this problem I added the following whenever A B C D E is selected:

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

Just wondering whether this is the correct solution or whether I should be doing something different?

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
PJL
  • 18,735
  • 17
  • 71
  • 68

7 Answers7

258

Well there are a few ways to go about this depending on the intended behavior, but this link should give you all the best solutions and not surprisingly is from Dianne Hackborn

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

Essentially you have the following options

  • Use a name for your initial back stack state and use FragmentManager.popBackStack(String name, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • Use FragmentManager.getBackStackEntryCount()/getBackStackEntryAt().getId() to retrieve the ID of the first entry on the back stack, and FragmentManager.popBackStack(int id, FragmentManager.POP_BACK_STACK_INCLUSIVE).
  • FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) is supposed to pop the entire back stack... I think the documentation for that is just wrong. (Actually I guess it just doesn't cover the case where you pass in POP_BACK_STACK_INCLUSIVE),
inazaruk
  • 74,247
  • 24
  • 188
  • 156
Joachim
  • 2,761
  • 1
  • 15
  • 7
  • What does this mean? FragmentManager.getBackStackEntryCount()/getBackStackEntryAt().getId() – dannyroa Aug 10 '12 at 02:14
  • 5
    2nd worked for me. What it means for clearing the entire stack: getSupportFragmentManager().popBackStack(getSupportFragmentManager().getBackStackEntryAt(0).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE); – NickL Nov 14 '12 at 16:23
  • @JorgeGarcia is it possible after popbackstack we just finish our fragment without restart older one. – duggu Sep 28 '13 at 03:41
  • Please note there is also the popBackStackImmediate() version since popBackStack() is async, meaning the clearing up does not occur at the exact moment you call the method. – Genc Sep 05 '16 at 10:15
  • 7
    Claims the group is banned as spam and i cannot access the link :( does anyone have the resource elsewhere? – EpicPandaForce May 09 '17 at 13:07
  • What if I have multiple fragments in flow like A-->B--->C-->D and from D if I want to go back to C and then to B and at last to A. But Above options always land me to A if I clicked back on B/C/D. What should be the proper way to manage this? – NGR Jul 02 '17 at 10:36
  • @NGR, simply `FragmentManager.popBackStack()` at every step. – CoolMind Dec 16 '19 at 10:18
62

The other clean solution if you don't want to pop all stack entries...

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

This will clean the stack first and then load a new fragment, so at any given point you'll have only single fragment in stack

EC84B4
  • 7,676
  • 4
  • 23
  • 34
Pawan Maheshwari
  • 15,088
  • 1
  • 48
  • 50
  • 1
    This is very bad: `getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);` before a replace() because are loading the Fragment calling `onCreateView()`, `onActivityCreated()`, etc. Restoring and Destroing a Fragment instantly is bad. The Fragment can register a receiver for example. This affects the performance. – VasileM May 10 '19 at 17:35
  • @VasileM, could you describe in details? In what cases it is bad? Is it because of asynhronous behaviour of `FragmentTransaction`? Is there only bad performance of wrong fragment stack? – CoolMind Dec 16 '19 at 09:59
  • @VasileM for that it could be a good practice to register observer and other jobs in OnViewCreated Fragment flow callback, or handle unregisering observers when the currently fragment is destroyed ' override fun onDestroy() { super.onDestroy() viewModel.viewState.removeObservers(this) } ' – Aury0n Mar 30 '21 at 16:02
28

Thanks to Joachim answer, I use the code to clear all back stack entry finally.

// 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 */
CoolMind
  • 26,736
  • 15
  • 188
  • 224
Jay Parker
  • 631
  • 11
  • 23
  • 18
    Why do use a loop here? For me FragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) cleared all back stack entry... – Marek May 22 '13 at 04:51
  • 3
    @Marek, because sometimes not all fragments should be removed, a loop is suitable for this. – CoolMind Dec 08 '16 at 18:07
  • 2
    @CoolMind, that still doesn't make sense to me. `popBackStack(backStackId, INCLUSIVE)` will pop all the fragments (states) back to backStackId, so once you pop the lowest `i` that you're going to pop, all the higher ones should get popped at the same time. So what's the point of a loop? – LarsH Nov 13 '19 at 15:02
  • @LarsH, you are right. See https://stackoverflow.com/a/59158254/2914140. In order to pop other fragments to required tag, we should first add the fragment with addToBackStack(**tag**). – CoolMind Dec 16 '19 at 09:31
7

I have researched a lot for cleaning Backstack, and finally see Transaction BackStack and its management. Here is the solution that worked best for me.

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

The above method loops over all the transactions in the backstack and removes them immediately one at a time.

Note: above code sometime not work and i face ANR because of this code,so please do not try this.

Update below method remove all fregment of that "name" from backstack.

FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack("name",FragmentManager.POP_BACK_STACK_INCLUSIVE);
  • name If non-null, this is the name of a previous back state to look for; if found, all states up to that state will be popped. The
  • POP_BACK_STACK_INCLUSIVE flag can be used to control whether the named state itself is popped. If null, only the top state is popped.
Community
  • 1
  • 1
Lokesh
  • 3,247
  • 2
  • 33
  • 62
  • I don't see why you would remove them one at a time. Is there a reason why you chose for this solution instead of the other solutions? Is there a reason to remove them one at a time instead of all at once? – miva2 Nov 26 '15 at 13:23
  • thair no method to remove backstack at one time see http://developer.android.com/reference/android/app/FragmentManager.html – Lokesh Nov 26 '15 at 16:45
3

I'm using a similar code as those that use the while loop but I call the entry count in every loop... so I suppose it's somewhat slower

FragmentManager manager = getFragmentManager();
while (manager.getBackStackEntryCount() > 0){
        manager.popBackStackImmediate();
    }
0

As written in How to pop fragment off backstack and by LarsH here, we can pop several fragments from top down to specifical tag (together with the tagged fragment) using this method:

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

Substitute "frag" with your fragment's tag. Remember that first we should add the fragment to backstack with:

fragmentTransaction.addToBackStack("frag")

If we add fragments with addToBackStack(null), we won't pop fragments that way.

CoolMind
  • 26,736
  • 15
  • 188
  • 224
-4
    // pop back stack all the way
    final FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
    int entryCount = fm.getBackStackEntryCount(); 
    while (entryCount-- > 0) {
        fm.popBackStack();
    }
farid_z
  • 1,673
  • 21
  • 11