My scenario : Activity 1 consists of Fragments A-> B-> C. All the fragments are added using this code :
FragmentManager fm = getSupportFragmentManager()
You need to do 2 things - name the FragmentTransaction from A->B and then override onBackPressed() in your containing activity to call FragmentManager#popBackStack (String name, int flags) when you are on Fragment C. Example:
Transition from A->B
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.container, new FragmentB(), "FragmentB")
.addToBackStack("A_B_TAG")
.commit();
Transition from B->C will use a similar transaction with "FragmentC" as its tag.
Then in your containing Activity override onBackPressed():
@Override
public void onBackPressed() {
if (getSupportFragmentManager().findFragmentByTag("FragmentC") != null) {
// I'm viewing Fragment C
getSupportFragmentManager().popBackStack("A_B_TAG",
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else {
super.onBackPressed();
}
}
Theory
Use the addToBackStack(tag: String): FragmentTransaction method from within the FragmentTransaction
in order to mark a point where you want to return to. This method returns the FragmentTransaction
instance for chain-ability only.
Then Return with the popBackStackImmediate(tag: String, flag: int): void method from the FragmentManager
. The tag is what you specified before. The flag is either the constant POP_BACK_STACK_INCLUSIVE
to include the transaction marked or 0
.
Example
What follows is an example with the following layout having a FrameLayout
with id content_frame
where the fragments are loaded into.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<FrameLayout
android:id="@+id/content_frame"
android:layout_below="@id/textView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
The code below marks a fragment by it's fragment class name when replacing the content of the layout element with id content_frame
.
public void loadFragment(final Fragment fragment) {
// create a transaction for transition here
final FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
// put the fragment in place
transaction.replace(R.id.content_frame, fragment);
// this is the part that will cause a fragment to be added to backstack,
// this way we can return to it at any time using this tag
transaction.addToBackStack(fragment.getClass().getName());
transaction.commit();
}
And to complete this example a method that allows you to get back to that exact same fragment using the tag when you loaded it.
public void backToFragment(final Fragment fragment) {
// go back to something that was added to the backstack
getSupportFragmentManager().popBackStackImmediate(
fragment.getClass().getName(), 0);
// use 0 or the below constant as flag parameter
// FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
When implementing this for real you might want to add a null check on the fragment parameter ;-).
This is how I do it..
With FragmentA.java and any other fragments.
Replace your fragment with its class name as tag:
private void showFragment(Fragment fragment){
if(fragment != null){
getSupportFragmentManager().beginTransaction().replace(R.id.container,fragment,fragment.getClass().getSimpleName()).commit();
}
}
Now in onBackPressed():
@Override
public void onBackPressed()
{
if(getSupportFragmentManager().findFragmentByTag("FragmentA") == null)
showFragment(new FragmentA());
else
super.onBackPressed();
}