I have an application using a navigation drawer. The drawer lets you navigate between 2 fragments : F1 and F2 :
Activity layout:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"/>
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:dividerHeight="0dp"
android:background="#f5f5f5"/>
</android.support.v4.widget.DrawerLayout>
Code to replace fragment in Activity :
private void selectItem(int position) {
Fragment fragment;
fragment = getFragmentToDisplay(position);
if(fragment != null)
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.content_frame, fragment,"fragment_"+position)
.commit();
}
}
On F1 i have a button to call an other fragment (F3). When F3 replace F1 i use addToBackStack()
to be able to return to F1 by pressing return.
Replacing F1 by F3:
getFragmentManager().beginTransaction()
.replace(R.id.content_frame, new GameFragment())
.addToBackStack("Games").commit();
Going from F1 to F2 , F2 to F1 works perfectly.
Going from F1 to F3 , F3 to F1 (using back button) works too.
Nevertheless if i'm doing this sequence :
F1 to F3 by button.
F3 to F2 by navigation drawer.
F2 to F1 by back button (backstack).
F1 to F2 by navigation drawer
The last fragment (F2) does not replace F1 , instead it appears above , like if i have added it :
Doing the same navigation but not using the back button works as expected.
Why the backstack is messing with the fragment replacement ?
My goal is to provide a back navigation between F1 and F3 but not between fragments accessed by the navigation drawer.
Let's understand what happens at each step:
Since addToBackStack
is called, a back stack entry is created for this transaction. In the back stack entry 2 operations are recorded:
op1: remove F1
op2: add F3
In case of navigation drawer you have not used addToBackStack
, there by the back stack is completely unaware of this transaction in which F3 is removed and F2 is added.
On back button press, the last recorded back stack entry's operation will be reversed. The last recorded entry was remove F1 & add F3. The expected result would be:
op1: remove F1 => add F1
op2: add F3 => remove F3
Since F3 was already removed in previous transaction, there is no-op. Back stack is completely unaware about F2 and hence is left as it is. By end of this transaction, both F1 and F2 are added to the activity window. Since F1 size is bigger than F2, it is not seen.
This transaction will just bring F2 on top of F1, as both were already added to the activity window.
Solution: Since the back navigation should happen only between F1 & F3, the moment user uses navigation drawer to navigate to different fragment, just clear the back stack.
FragmentManager fm = getActivity().getFragmentManager();
for(int i = 0; i < fm.getBackStackEntryCount(); i++) {
fm.popBackStack();
}