How to replace fragment C with fragment A when back button is pressed?
Asked Answered
R

3

37

My scenario : Activity 1 consists of Fragments A-> B-> C. All the fragments are added using this code :

        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();
        ft.replace(R.id.content, fragment, TAG);
        ft.addToBackStack(TAG);
        ft.commit();

Now, from fragment C, I want to directly return to Fragment A. Therefore, I've commented ft.addToBackStack(TAG) while adding Fragment C. So when I press back button from C I directly get Fragment A on the screen.

However, Fragment C is not replaced by A. In fact, both the fragments are visible. How do I solve this issue?

Rutherfurd answered 21/12, 2012 at 5:44 Comment(0)
R
21

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 ;-).

Roque answered 27/9, 2013 at 15:51 Comment(1)
my fragment is the TAB A in actionbar, when tap on TAB A, I call the main activity to replace the TAB A content with another fragment with the code getFragmentManager().beginTransaction().replace(R.id.container, newFragment) .addToBackStack(null).commit(); However, no back btn id displayed for me to go back to the TAB A. Any idea?Terminable
U
31

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();
  }
}
Unnumbered answered 5/2, 2013 at 18:18 Comment(2)
Are you sure that this line is correct?: .replace(new FragmentB(), "FragmentB") I don't think soPenetrate
.replace(new FragmentB(), "FragmentB") should be .replace(R.id.container, new FragmentB(), "FragmentB") Trebuchet
R
21

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 ;-).

Roque answered 27/9, 2013 at 15:51 Comment(1)
my fragment is the TAB A in actionbar, when tap on TAB A, I call the main activity to replace the TAB A content with another fragment with the code getFragmentManager().beginTransaction().replace(R.id.container, newFragment) .addToBackStack(null).commit(); However, no back btn id displayed for me to go back to the TAB A. Any idea?Terminable
O
0

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();
    }
Oestrone answered 2/12, 2020 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.