pdpiech pdpiech - 11 months ago 63
Android Question

Proper/Best Way to Handle Android Fragment Transaction Issue

In my open source Android app, an issue has been discovered where a specific fragment will come into view on top of another fragment or crash the app in a certain situation.

The issue on GitHub if you want to see more information and example screenshots:

I have pinned down the reason, but want to know which of the methods in the android.support.v4.app package to use to resolve the issue.


, is the code for the navigation drawer that uses
to switch fragments.

The issue arises because in
, I use:

ViewMapFragment vmf = new ViewMapFragment();
FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, vmf);

And in

FragmentManager fm = getSherlockActivity().getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();

properly removes the
from view, but if you have it in view and use the navigation drawer to change to a different fragment,
is still on the back stack.

So, for my questions:

1) How do I check if a particular fragment is on the back stack before attempting to remove/replace it, or will the app not crash if you attempt when nothing is there (i.e. not checking)? E.g. calling
when there is nothing on the back stack.

2) Should I use
class methods to attempt to remove the
from the back stack or should I use
methods? Pros vs cons?

3) What is the difference in the UI between
? Does the user see some glitchy transitions?

Answer Source

According to the documentation of FragmentTransaction, when you invoke addToBackStack method it just remembers what actions you perform in that transaction. When popBackStack method is invoked it will reverse those actions and execute them.

So, what happens:

  1. When we go from MapFragment to ViewMapFragment, FragmentManager remembers removing MapFragment and adding ViewMapFragment operations.
  2. Then we go to any other fragment using Navigation Drawer, which causes ViewMapFragment removing operation, and after that it adds fragment selected from Drawer.
  3. Finally, when we press Back button, popBackStackImmediate is invoked and FragmentManager executes reversed operations: ViewMapFragment is removed (actually it is removed already) and MapFragment is added. And here is the problem occurs - the selected fragment is still there, so we have two fragments on the screen at the same time.

There is several options to handle such a situation:

  1. Simply add Navigation Drawer operations to back stack.
  2. Clear back stack every time when fragment switching is started by Navigation Drawer.

To clear back stack you can use this code (related question):

getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);

If you put this line in the beginning of your selectItem method the bug will be fixed.

And your questions:

  1. You can check whether a fragment is in a back stack by using FragmentManager.findFragmentByTag method. See example in the end of my answer.
  2. An entry of back stack technically can contain several fragments, and I don't think there is a way to remove single fragment from it. Instead of removing you can just clear back stack (please, refer this question).
  3. The main difference is that popBackStack will give you a chance to do something, before it actually starts popping process (it will be started when application returns to it's event loop).

Example. For instance, we have added a fragment with tag "fragment-1":

        .replace(R.id.frame, new TestFragment(), "fragment-1")

Then, we put it into a back stack and replace it with another fragment:

        .replace(R.id.frame, new TestFragment(), "another-fragment")

At this point getSupportFragmentManager().findFragmentByTag("fragment-1") returns our first fragment (it gets it from a back stack entry). Now we can check whether this fragment is added to its activity by isAdded method - if it returns false, then we can make an assumption that the fragment is in a back stack.