So, there are some similar questions, but I have not found a single one solving this issue. The official android documentation seems intuitive but when I implement an app with a more complicated workflow, the fragments backstack gets messy and weird stuff starts happening. I developed a skeleton for simple apps, with the idea of a single activity which can be accessed by its fragments to start other fragments. This is how I did it:
1- I let my main activity implement an interface called "FragmentDelegate"
public interface FragmentDelegate {
public void startFragment(CCFragment fragment, boolean addToBackStack);
}
2- The implementation of the startFrargment method:
@Override
public void startFragment(CCFragment fragment, boolean addToBackStack) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragment.setFragmentDelegate(this);
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right,
R.anim.slide_out_left, R.anim.slide_in_left,
R.anim.slide_out_right);
fragmentTransaction.replace(CONTENT_VIEW_ID, fragment,
"callerFragmentClassName");
if (addToBackStack)
fragmentTransaction.addToBackStack("callerFragmentClassName");
fragmentTransaction.commitAllowingStateLoss();
}
The cool thing about this is, I can call from any fragment:
mFragmentDelegate.startFragment(aNewFragment, addToBackStack);
OK now think of the following case scenario:
I start my activity with an initial fragment, lets say fragment A. From fragment A, I call the Camera Activity for a result. When the result arrives, I start Fragment B (adding A to the backstack). From B I start Fragment C without adding B to the backstack. So we have this in the backstack:
[A] [C]
If I press the back button, I get back to A. If I repeat the process, the backstack gets messed up and when I press back, it takes me to the C fragment again and again...
I know this is difficult to understand (and more difficult for me to explain, because English is not my mother tongue) but if someone could explain to me how do the android fragments backstack really work, or provide some kind of skeleton for an app, would be great.
Explanation:
When the FragmentManager reverts saved FragmentTransactions (e.g. the user click the Back button or you called some pop method on it), it executes the opposite of the action that's stored in the saved FragmentTransaction. You can see the exact code here, it's pretty straightforward.
In your case, the saved operation type is 'replace', so reverting that means removing all added Fragment instances and re-adding the removed one. So when you have a fragment stack like this:
[A] [B]
FragmentManager knows, that is has to remove the [B] Fragment instance and add the [A] upon a pop operation. The problem is, that you replaced [B] with [C]:
[A] [C]
Unfortunately, the saved Fragment BackStack entry does not know about [C]. So during a pop operation, the FragmentManager will re-add [A], will not find [B] so it does nothing about that, and leave [C] where it is.
Solution
One possible solution for this problem is using child fragments. Fragment-A is a top-level Fragment, but Fragment-B and Fragment-C are child fragments of a WrapperFragment.
Basically, when you navigate to Fragment-B, you replace Fragment-A with the WrapperFragment in a saved transaction:
[A] [[B]]
Afterwards, when the user navigates to Fragment-C, you only replace the WrapperFragment's [B] with [C]:
[A] [[C]]
When the user presses the Back button, we'll correctly get back to Fragment-A:
[A]
Demo
I've assembled a GitHub project to demonstrate this technique.
I can't figure out how you ended up with popping C fragments again and again without whole picture of what you did, but here what you got wrong about backstack:
BackStack
entry actually saves the current state of whole
FragmentManager
, not just single fragment. I.e. if you perform
multiple operations with multiple fragments in single a transaction and
call addToBackStack()
, you'll save the state of all fragments in
the upcoming transaction.
When you call addToBackStack()
you actually adding the next
state to the backstack, i.e. actually, if you've called
addToBackStack()
when you've added A fragment, you actually have a state
with B and a state with A behind it -- [A] [B], not [A] [C].
I recommend you to use this code
and try everything with debugger looking at a state of
FragmentManager
object:
int count = fragmentManager.getBackStackEntryCount();
fragmentTransaction.addToBackStack(String.valueOf(count));
This way you'll be able to trace what's really going on in your app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With