31

I have only one activity and multiple fragments in my application.

Two main fragment A(left) and B(right).

Fragment A1 called from A

B1 called from B

B2 called from B1

All fragments have individual back buttons.

So when I press back button of fragment A1, it should go back to A, similarly when Back button from B2 is pressed, B1 appears and from B1 to B and so on.

How to implement this type of functionality?

abhishek gupta
  • 359
  • 1
  • 12
Mihir Shah
  • 1,799
  • 3
  • 29
  • 49
  • `All fragments have individual back buttons.` that makes absolutely no sense to me. Could you please further explain it? – Budius Jan 11 '13 at 10:02
  • Left fragmet A and right fragment B, I have 3 buttons in A. when pressing 1st button of A, A1 is displayed. I have listview in A1. when click on listview item, its detail appears on right side fragment B1. Same for other 2 buttons of A. – Mihir Shah Jan 11 '13 at 10:09

10 Answers10

41
public void onBackPressed()
{
    FragmentManager fm = getActivity().getSupportFragmentManager();
    fm.popBackStack();
}
Manitoba
  • 8,522
  • 11
  • 60
  • 122
27

I have implemented the similar Scenario just now.

Activity 'A' -> Calls a Fragment 'A1' and clicking on the menu item, it calls the Fragment 'A2' and if the user presses back button from 'A2', this goes back to 'A1' and if the user presses back from 'A1' after that, it finishes the Activity 'A' and goes back.

See the Following Code:

Activity 'A' - OnCreate() Method:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activityA);

    if (savedInstanceState == null) {
        Fragment fragInstance;

        //Calling the Fragment newInstance Static method
        fragInstance = FragmentA1.newInstance();

        getFragmentManager().beginTransaction()
                .add(R.id.container, fragInstance)
                .commit();
    }
}

Fragment : 'A1'

I am replacing the existing fragment with the new Fragment when the menu item click action happens:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.action_edit_columns) {
        //Open the Fragment A2 and add this to backstack
        Fragment fragment = FragmentA2.newInstance();
        this.getFragmentManager().beginTransaction()
                .replace(R.id.container, fragment)
                .addToBackStack(null)
                .commit();

        return true;
    }
    return super.onOptionsItemSelected(item);
}

Activity 'A' - onBackPressed() Method:

Since all the fragments have one parent Activity (which is 'A'), the onBackPressed() method lets you to pop fragments if any are there or just return to previous Activity.

@Override
public void onBackPressed() {
    if(getFragmentManager().getBackStackEntryCount() == 0) {
        super.onBackPressed();
    }
    else {
        getFragmentManager().popBackStack();
    }
}

If you are looking for Embedding Fragments inside Fragments, please refer the link: http://developer.android.com/about/versions/android-4.2.html#NestedFragments

TrueBlue
  • 321
  • 4
  • 5
  • 1
    I think this is the best answer, since you really don't want to forget to first "addToBackStack" your fragment. Otherwise, there's nothing to pop for the back! – Myoch Sep 27 '15 at 15:13
  • Yeah..Nobody mentioned the `addToBackStack` method. Thanks – h8pathak Jul 11 '16 at 09:38
  • currently, I'm also doing similar flow and this helps me a lot for handling back pressed. – scsfdev Jun 27 '18 at 06:59
17

@trueblue's answer got me going with one minor but annoying issue. When there is only one fragment on the backstack and you press back button, that frame is removed and the app remains active with a blank screen. User needed to press back button one more time to exit the app. I modified the original code to the following in order to handle this situation

@Override
public void onBackPressed() {
    if(getFragmentManager().getBackStackEntryCount() == 0) {
        super.onBackPressed();
    }
    else if(getFragmentManager().getBackStackEntryCount() == 1) {
        moveTaskToBack(false);
    }
    else {
        getFragmentManager().popBackStack();
    }
}

When there is only 1 fragment in the backstack, we are basically telling android to move the whole app to back.

Update (and probably a better answer)

So after doing some more reading around this, I found out that you can add fragment manager transactions to back stack and then android handles back presses automatically and in a desired way. The below code snippet shows how to do that

Fragment fragment; //Create and instance of your fragment class here
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

fragmentTransaction.replace(R.id.fragment_container, fragment).addToBackStack(null);
fragmentTransaction.commit();
fragmentTransaction.addToBackStack(null);

The last line shows how you add a transaction to back stack. This solves back press issue for fragments in most situations except for one. If you go on pressing back button, then eventually you will reach a point when there is only one fragment in the back stack. At this point, you will want to do one of the two things

  1. Remove the activity housing the fragment from the back stack of the task in which activity is running. This is because you do not want to end up with a blank activity
  2. If the activity is the only activity in the back stack of the task, then push the task in background.

In my case, it was the later, so I modified the overridden onBackPressed method from my previous answer to look like below

@Override
public void onBackPressed() {
    if(getFragmentManager().getBackStackEntryCount() == 1) {
        moveTaskToBack(false);
    }
    else {
        super.onBackPressed();
    }
}

This code is simpler because it has less logic and it relies on framework than on our custom code. Unfortunately I did not manage to implement code for first situation as I did not need to.

Community
  • 1
  • 1
Suhas
  • 7,919
  • 5
  • 34
  • 54
  • This needs a lot more votes ! works great for me. Thanks ! – Red M Aug 03 '16 at 04:42
  • I got java.lang.IllegalStateException: addToBackStack() called after commit() when I called addToBackStack(null) AFTER commit(); Moving it BEFORE fixed the issue – ymerdrengene Aug 25 '17 at 14:14
6

Just Do

getActivity().getFragmentManager().popBackStack();
HaveNoDisplayName
  • 8,291
  • 106
  • 37
  • 47
5

You have to implement your own backstack implementation as explained here.

You can call the popFragments() whenever you click the back button in a fragment and call pushFragments() whenever you navigate from one Fragment to other.

Community
  • 1
  • 1
TNR
  • 5,839
  • 3
  • 33
  • 62
1

Try this, Its Work for me.

public void onBackPressed() {
    if (mainLayout.isMenuShown()) {
        mainLayout.toggleMenu();
    } else {
        FragmentManager fm = getSupportFragmentManager();
        Log.print("back stack entry", fm.getBackStackEntryCount() + "");

        if (fm.getBackStackEntryCount() > 1) {
            fm.popBackStack();
            // super.onBackPressed();
            // return;
        } else {
            if (doubleBackToExitPressedOnce) {
                fm.popBackStack();
                super.onBackPressed();
                return;
            }

            this.doubleBackToExitPressedOnce = true;
            Toast.makeText(this, "Press one more time to exit",
                    Toast.LENGTH_SHORT).show();

            new Handler().postDelayed(new Runnable() {

                @Override
                public void run() {

                    doubleBackToExitPressedOnce = false;
                }
            }, 3000);

        }
    }
}
Shreyans Patel
  • 129
  • 1
  • 10
0

Back button will traverse in the order, in which Fragments were added to backstack. This is provided as a navigation function by default. Now if you want to go to specific Fragment, you can show it from backstack.

S.D.
  • 29,290
  • 3
  • 79
  • 130
0

You can handle it by adding tag in the backStack. Check my answer here :

https://stackoverflow.com/a/19477957/1572408

hope it helps

Community
  • 1
  • 1
Rudi
  • 4,304
  • 4
  • 34
  • 44
-1
@Override
public void onResume() {

    super.onResume();

    getView().setFocusableInTouchMode(true);
    getView().requestFocus();
    getView().setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {

            if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK){

                // replace your fragment here

                return true;

            }

            return false;
        }
    });
}

// Happy Coding

Hiren Patel
  • 52,124
  • 21
  • 173
  • 151
-1

If you press back image you have to create method first like this

private void Backpresses() {
    getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.contant_main, new Home()).commit();
}

then you have to call like this when you press back image..

 back.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                   Backpresses();

                }
            });

It work fine for me.

S HemaNandhini
  • 333
  • 3
  • 5