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?
FragmentManager
API for removing aFragment
state from the middle of the back stack. The API only exposes a standard stack mechanism for pushing and popping. – CrumFragmentManager
implementation. If you are willing to go to these lengths, then it should actually be fairly simple to implement. – CrumFragment
back stack by hand, with whatever functionality you need. You won't be able to make use of theBackStackRecord
class, as it depends on the stack model; it will have to be a custom solution. If you are interested, then I might write up an answer based on this in a few days when I have the time (or maybe someone else can). Or you can try doing it yourself if you like - it shouldn't be too difficult. – Crum