How to replace fragment C with fragment A when back button is pressed?
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():
@Overridepublic 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(); }