Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Reorder Fragment Backstack

Tags:

I have a number of pages/fragments listed in my navigation drawer, the user is likely to switch between these frequently and I want them in the backstack so that they can navigate back, but I only want one instance of each fragment in the backstack so that the user doesn't not have to press back an insane number of times to exit the app. I can't figure out how to effectively 'reorder' the backstack' without pages getting removed.

Currently when I change page I was using this code to change the fragment and make sure it's only in the back stack once

  if (mFragMgr == null) {
      mFragMgr = getSupportFragmentManager();
  }

  String backStateName = fragmentDescriptor.name();
  boolean fragmentPopped = mFragMgr.popBackStackImmediate(backStateName, 0);
  if (!fragmentPopped){
      mFragMgr.beginTransaction()
      .remove((Fragment) mFragment)
      .replace(R.id.content_frame, (Fragment) mFragment)
      .addToBackStack(backStateName)
      .commit();
  }

I use this code in onBackPressed

  @Override
  public void onBackPressed() {
      if (mFragMgr.getBackStackEntryCount() > 0) {
          mFragMgr.popBackStackImmediate();
      } else {
          super.onBackPressed();
      }
  }

This works but it means it removes pages I don't want removed. Example:

When my user visits 6 pages in the order A > B > C > D > E > C because I'm doing a remove I expected the following stack:

                            [E]    [C]
                     [D]    [D]    [E]
              [C]    [C]    [C]    [D]
       [B]    [B]    [B]    [B]    [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]

But what I actually get is the following - it pops everything up to the element that matches the name, this is regardless of whether I include the ".remove((Fragment) mFragment)" or not - (I've already realised now that remove isn't affecting the backstack, so no need to point that out):

                            [E]
                     [D]    [D]
              [C]    [C]    [C]    [C]
       [B]    [B]    [B]    [B]    [B]
[A] -> [A] -> [A] -> [A] -> [A] -> [A]

If I don't use a name and instead use null when adding to the backstack I get the following:

                                   [C]
                            [E]    [E]   
                     [D]    [D]    [D]    
              [C]    [C]    [C]    [C]   
       [B]    [B]    [B]    [B]    [B]  
[A] -> [A] -> [A] -> [A] -> [A] -> [A] 

How can I get the behaviour I expect? Is it possible at all or am I going to need to record the changes myself and skip the backstack altogether?

like image 775
Nick Cardoso Avatar asked Feb 09 '14 21:02

Nick Cardoso


People also ask

What is addToBackStack null?

This means that the transaction will be remembered after it is committed, and will reverse its operation when later popped off the stack.

How do you move from one fragment to another in Kotlin?

setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Fragment fragment = new tasks(); FragmentManager fragmentManager = getActivity(). getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager. beginTransaction(); fragmentTransaction. replace(R.

How do I move a fragment to an activity?

Can I go from fragment to activity Android? You can add your fragment to the activity's view hierarchy either by defining the fragment in your activity's layout file or by defining a fragment container in your activity's layout file and then programmatically adding the fragment from within your activity.


1 Answers

There is no API to do this, but becuse I was wondering the same thing last week,
I took it as an exercise an implemented it myself.

My method allows you to remove a Fragment from anywhere in the backstack and this is achieved by using refrection to modify the internal variables that store the backstack information in FragmentManagerImpl and BackStackRecord.

There are few important variables:

  • mBackStack - stores the BackStackRecords that hold the Fragment info, the previous ones, animations, etc
  • mActive - all added Fragments
  • mAvailBackStackIndices - stores the indices that can be used by the newly inserted records, i.e. indices of null values in mActive
  • and other

Tested with 150+ Fragments and couldn't notice any leaks, but only monitored the heap in DDMS and did not perform any other memory analysis.
So because someting may be broken, explore the code, re-test it, see if anyone provides a better answer, and rethink if you really need to do this in your project.

I uploaded the code as a gist on GitHub, hope it helps.

like image 156
jankovd Avatar answered Sep 19 '22 14:09

jankovd