androidfragment-backstackfragment-transitions

How to replace more than one fragments with another one in the back stack?


I have the following fragments in the back stack A, B, C. Then I want to add fragment D, but in the back stack I want to put A and D instead of A, B, C, D. The problem is when I try to remove B and C with transaction.remove(), the backStackEntryCount is still the old one, which makes empty screens while pressing back. Is there a way to handle this?

When I use popBackStack()it goes to fragment A then comes D, which makes weird animation effects.

EDIT: The question is not duplicate as it was marked, because this question is more about to control the order of several fragments in the back stack.


Solution

  • When adding to the Backstack, you can include a name to pop the backstack to when you're in a specific state. Based on the documentation for FragmentManager#popBackStack(string, int);:

    Pop the last fragment transition from the manager's fragment back stack. If there is nothing to pop, false is returned. This function is asynchronous -- it enqueues the request to pop, but the action will not be performed until the application returns to its event loop.

    Parameters

    name String: 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.

    flags int: Either 0 or POP_BACK_STACK_INCLUSIVE.

    So in this case you:

    Add fragment A to the container and to the root backstack. Give it a name so you can reference it when popping.

    Fragment A:

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
    .replace(R.id.fragment_container, FragmentA, "FragmentA")
    .addToBackStack("first")
    .commit();
    

    Add Fragment B to the container (replace or add, doesn't matter). Add to the backstack with a "null" or another name if you prefer. It must be different than "first".

    Fragment B:

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
    .replace(R.id.fragment_container, FragmentB, "FragmentB")
    .addToBackStack(null)
    .commit();
    

    Add or replace with Fragment C like you would with Fragment B.

    Fragment C:

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
    .replace(R.id.fragment_container, FragmentC, "FragmentC")
    .addToBackStack(null)
    .commit();
    

    Add or replace with Fragment D like you would with Fragment B and C.

    Fragment D:

    FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction()
    .replace(R.id.fragment_container, FragmentD, "FragmentD")
    .addToBackStack(null)
    .commit();
    

    Then, in onBackPressed() you first check if "FragmentD" is in the stack. If it is, then pop all the way back to the root (which in this case is "first"). If not, just handle the back pressed like you normally would.

    @Override
    public void onBackPressed() {
        FragmentManager fm = getFragmentManager();
        if (fm.findFragmentByTag("FragmentD") != null) {
           fm.popBackStack("first", 0); // Pops everything up to "first" 
        } else {
           super.onBackPressed(); // Pops backstack like normal or leaves App if at base.
        }
    }
    

    What this should do is allow your users to go "back" when they press the back button in Fragments A, B, or C. Then when they're finally in Fragment D, it will pop all the way back to A.