374

I have some fragments in my activity

[1], [2], [3], [4], [5], [6]

And on Back Button Press I must to return from [2] to [1] if current active fragment is [2], or do nothing otherwise.

What is the best practise to do that?

EDIT: Application must not return to [2] from [3]...[6]

zmarties
  • 4,809
  • 22
  • 39
skayred
  • 10,603
  • 10
  • 52
  • 94
  • 1
    Put it differently, you want Fragment [1] to be root and all other Fragments ([2]...[6]) to be on next level (i.e. root's children). That means, you can navigate back to root (not child) from any child. Is this correct? –  Sep 12 '15 at 17:27
  • 3
    It is very important to first understand how onBackPressed() works by default for fragments... The answer is short: it first searches for any added fragment via addToBackStack, if there is one, it does exactly the same as popBackStack() to pop it, otherwise it does the default onBackPressed() for the activity. So, care must be taken in the way you add fragments. As an example, If you add Fragment B to an existing Fragment A via add() method but without addToBackStack(), then onBackPressed() will NOT pop Fragment B to get back to Fragment A, but causes onStop() on the parent activity. – Ali Nem Sep 27 '17 at 11:15
  • 1
    Anybody can give the answer here : https://stackoverflow.com/questions/63760586/kotlin-handling-back-button-click-in-navigation-drawer-android – Jaimin Modi Sep 07 '20 at 14:02

25 Answers25

436

When you are transitioning between Fragments, call addToBackStack() as part of your FragmentTransaction:

FragmentTransaction tx = fragmentManager.beginTransation();
tx.replace( R.id.fragment, new MyFragment() ).addToBackStack( "tag" ).commit();

If you require more detailed control (i.e. when some Fragments are visible, you want to suppress the back key) you can set an OnKeyListener on the parent view of your fragment:

//You need to add the following line for this solution to work; thanks skayred
fragment.getView().setFocusableInTouchMode(true);
fragment.getView().requestFocus();
fragment.getView().setOnKeyListener( new OnKeyListener()
{
    @Override
    public boolean onKey( View v, int keyCode, KeyEvent event )
    {
        if( keyCode == KeyEvent.KEYCODE_BACK )
        {
            return true;
        }
        return false;
    }
} );
cV2
  • 5,229
  • 3
  • 43
  • 53
Mark Allison
  • 21,839
  • 8
  • 47
  • 46
  • 1
    In my case, I must clear back stack when [2] goes to [3], so addToBackStack working wrong – skayred Nov 03 '11 at 09:23
  • 91
    Handling OnKey from View does not work – skayred Nov 03 '11 at 09:41
  • 1
    Doesn't seem to be working for me either. Any idea why, Mark? – nmr Dec 27 '11 at 16:42
  • 1
    @Ixx this works just fine, if you have a problem with Eclipse not accepting `new OnKeyListener()` as a parameter, type it manually, there must be a copy/paste issue despite the writing is correct. – A-Live Jul 12 '12 at 00:43
  • 15
    I confirm that setOnKeyListener does't work for me, back button still cause go to older fragment. – ATom Jul 30 '12 at 15:32
  • 1
    @skayred Your earlier comment says that OnKey from View doesn't work, yet you marked this as the correct answer. Did you figure out why it wasn't working? Please share, as it isn't working for me either. – HotN Oct 25 '12 at 17:08
  • 1
    Another good approach for handling Back Key for Fragment then you can go with this http://developer.android.com/training/implementing-navigation/temporal.html which is developer site. – Herry Dec 13 '12 at 07:26
  • 1
    i try above answer code but it's not working to detect back key press for Fragment which currently shown. – Herry Dec 13 '12 at 07:27
  • 2
    it does not work, cause the view got no focus use the other answer that work partial! – Kani Dec 17 '12 at 12:40
  • 1
    Dmitry Zaitsev answer should be marked as correct. – kamil zych Mar 07 '13 at 15:54
  • 30
    If you want this to work you must call `fragment.getView().setFocusableInTouchMode(true);`. – goncalossilva Jun 20 '13 at 09:09
  • 1
    is working after @goncalossilva 's fix; TESTED – Dheeraj Bhaskar May 19 '14 at 22:20
  • 14
    Works OK, but getView().requestFocus() must be also added – G. Kh. Jul 24 '14 at 13:29
  • 5
    In this implementation, the onKey method gets called 2 times. To prevent this from happening we need to check this, if (event.getAction() == KeyEvent.ACTION_DOWN) { // Rest of the code goes here } – Aritra Roy Feb 04 '15 at 15:32
  • 21
    This solution only work when you dont have any requestFoucus item into your view..once you change your request from root view to other element of view such as edit text then it won't work at all... – Swap-IOS-Android Feb 24 '15 at 17:16
  • 1
    its not work for me...nothing to change after add this code. – Pranav P Apr 22 '15 at 12:15
  • 1
    Like @Swap-IOS-Android said it works only if in your fragment there's no any other view calling "RequestFocus"! – Francesco May 05 '15 at 12:46
  • 1
    @Swap-IOS-Android is right, if not work when u use this answer, there maybe other view calling RequestFocus, ex EditText, you can setOnKeyListener of them also – Trinea Jun 10 '15 at 03:18
  • 1
    @Swap-IOS-Android that's correct. it won't work – david Oct 03 '15 at 08:54
  • 1
    This is not a proper way if you intend to obey Android core quality rules, which require not to overwrite back button action http://developer.android.com/distribute/essentials/quality/core.html – Marek Oct 18 '15 at 15:03
  • 1
    How can I make the back button go back to only one fragment? – Sauron Jan 15 '16 at 03:15
  • 1
    @Swap-IOS-Android, please check http://stackoverflow.com/questions/18755550/fragment-pressing-back-button/27145007?noredirect=1#comment59201880_27145007 one – Hiren Patel Mar 03 '16 at 08:08
  • 1
    Simple and clear answer, works fine for me but i'am interested where what the function of the given string is. Where is this used for? – CodeNinja Mar 14 '16 at 11:27
  • 1
    We can also use `mBinding.getRoot().setFocusableInTouchMode(true);` `mBinding.getRoot().requestFocus();` when we are using Data Binding. – Naresh Nov 29 '17 at 10:04
  • 1
    `fragment.getView()` gives me null. How to solve this? – khateeb Jul 12 '18 at 07:03
  • Beware of showing dialog in onResume of fragment.! – Sumit Shukla Jul 09 '20 at 10:05
  • Anybody can give the answer here : https://stackoverflow.com/questions/63760586/kotlin-handling-back-button-click-in-navigation-drawer-android – Jaimin Modi Sep 07 '20 at 14:02
  • @khateeb you can access the view which are inflating in the onCreateView and then use that view to access the methods. – Anubhav Nov 12 '20 at 05:36
  • If you have nested fragments inside a fragment this won't work for them.. – Serdar Samancıoğlu Apr 22 '22 at 11:52
275

I'd rather do something like this:

private final static String TAG_FRAGMENT = "TAG_FRAGMENT";

private void showFragment() {
    final Myfragment fragment = new MyFragment();
    final FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment, fragment, TAG_FRAGMENT);
    transaction.addToBackStack(null);
    transaction.commit();
}

@Override
public void onBackPressed() {
    final Myfragment fragment = (Myfragment) getSupportFragmentManager().findFragmentByTag(TAG_FRAGMENT);

    if (fragment.allowBackPressed()) { // and then you define a method allowBackPressed with the logic to allow back pressed or not
        super.onBackPressed();
    }
}
Pedro Andrade
  • 4,556
  • 1
  • 25
  • 24
134

if you overide the onKey method for the fragment view you're gonna need :

    view.setFocusableInTouchMode(true);
    view.requestFocus();
    view.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                Log.i(tag, "keyCode: " + keyCode);
                if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
                    Log.i(tag, "onKey Back listener is working!!!");
                    getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    return true;
                } 
                return false;
            }
        });
ANemati
  • 4,766
  • 3
  • 20
  • 13
99

Use addToBackStack method when replacing one fragment by another:

getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).addToBackStack("my_fragment").commit();

Then in your activity, use the following code to go back from a fragment to another (the previous one).

@Override
public void onBackPressed() {
    if (getParentFragmentManager().getBackStackEntryCount() > 0) {
        getParentFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
}
Yury Matatov
  • 805
  • 3
  • 11
  • 23
shimatai
  • 1,759
  • 16
  • 18
58

If you want to handle hardware Back key event than you have to do following code in your onActivityCreated() method of Fragment.

You also need to check Action_Down or Action_UP event. If you will not check then onKey() Method will call 2 times.

Also, If your rootview(getView()) will not contain focus then it will not work. If you have clicked on any control then again you need to give focus to rootview using getView().requestFocus(); After this only onKeydown() will call.

getView().setFocusableInTouchMode(true);
getView().requestFocus();

getView().setOnKeyListener(new OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (keyCode == KeyEvent.KEYCODE_BACK) {
                        Toast.makeText(getActivity(), "Back Pressed", Toast.LENGTH_SHORT).show();
                    return true;
                    }
                }
                return false;
            }
        });

Working very well for me.

Tejas Mehta
  • 1,629
  • 13
  • 9
38

Create interfaces:

BackButtonHandlerInterface

public interface BackButtonHandlerInterface {
    void addBackClickListener (OnBackClickListener onBackClickListener);
    void removeBackClickListener (OnBackClickListener onBackClickListener);
}

OnBackClickListener

public interface OnBackClickListener {
     boolean onBackClick();
}

In Activity:

public class MainActivity extends AppCompatActivity implements BackButtonHandlerInterface {

    private ArrayList<WeakReference<OnBackClickListener>> backClickListenersList = new ArrayList<>();

    @Override
    public void addBackClickListener(OnBackClickListener onBackClickListener) {
        backClickListenersList.add(new WeakReference<>(onBackClickListener));
    }

    @Override
    public void removeBackClickListener(OnBackClickListener onBackClickListener) {
        for (Iterator<WeakReference<OnBackClickListener>> iterator = backClickListenersList.iterator();
         iterator.hasNext();){
            WeakReference<OnBackClickListener> weakRef = iterator.next();
            if (weakRef.get() == onBackClickListener){
                iterator.remove();
            }
        }
    }

    @Override
    public void onBackPressed() {
        if(!fragmentsBackKeyIntercept()){
            super.onBackPressed();
        }
    }

    private boolean fragmentsBackKeyIntercept() {
        boolean isIntercept = false;
        for (WeakReference<OnBackClickListener> weakRef : backClickListenersList) {
            OnBackClickListener onBackClickListener = weakRef.get();
            if (onBackClickListener != null) {
                boolean isFragmIntercept = onBackClickListener.onBackClick();
                if (!isIntercept) isIntercept = isFragmIntercept;
            }
        }
        return isIntercept;
    }
}

In Fragment:

public class MyFragment extends Fragment implements OnBackClickListener{

    private BackButtonHandlerInterface backButtonHandler;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        backButtonHandler = (BackButtonHandlerInterface) activity;
        backButtonHandler.addBackClickListener(this);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        backButtonHandler.removeBackClickListener(this);
        backButtonHandler = null;
    }

    @Override
    public boolean onBackClick() {
        //This method handle onBackPressed()! return true or false
        return false;
    }

}

Update

Provide custom back navigation

class MyFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // This callback will only be called when MyFragment is at least Started.
        val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
        }

        // The callback can be enabled or disabled here or in the lambda
    }

}
krawa
  • 583
  • 6
  • 12
  • 1
    Though requires little more coding...But it is better for device back button press handle...+1 – Android Killer Feb 19 '16 at 07:34
  • And why do You use WeakReference, if You remove listeners in Fragment's onDetach() ? :) – Victor Oct 17 '18 at 08:27
  • I think this is more complicated and will need more code to write, am not with this kind of solving issues – blueware Feb 28 '19 at 14:08
  • 1
    The last update was so useful and quick to understand I really advise anyone that uses navigation component and want to hand the back action directly form the fragment without the hassle of passing the method callbacks from activity to the currently displayed fragment. – Mina Samir Jul 21 '20 at 01:30
  • Anybody can resolve this : https://stackoverflow.com/questions/63760586/kotlin-handling-back-button-click-in-navigation-drawer-android – Jaimin Modi Sep 07 '20 at 14:05
29

The most ideal way of doing this is found here: Fragment: which callback invoked when press back button & customize it

public class MyActivity extends Activity
{
    //...
    //Defined in Activity class, so override
    @Override
    public void onBackPressed()
    {
        super.onBackPressed();
        myFragment.onBackPressed();
    }
}

public class MyFragment extends Fragment
{
    //Your created method
    public static void onBackPressed()
    {
        //Pop Fragments off backstack and do your other checks
    }
}
Community
  • 1
  • 1
kakoma
  • 1,179
  • 13
  • 17
  • 3
    but it says The method onBackPressed() is undefined for the type Fragment – Maveňツ Jul 24 '14 at 12:21
  • 1
    You need to create the method yourself, you dont override it. It can also be called anything you like. – Squeazer Jul 25 '14 at 08:44
  • 1
    This method looks clean, but what do you do if more than one fragment handles the back button press differently? Say for example, fragment A is visible to the user and they hit the back button. How can you ensure that the activity is invoking the correct onBackPressed() method, if fragment B also uses a separate onBackPressed method? – h_k Aug 14 '14 at 18:56
  • 1
    I solved my above problem. In the activity's onBackPRessed method, I performed a java `switch` on my ViewPager's `getCurrentItem()` method. This returns an integer value representing the page the user is currently looking at. Doing this enabled me to single out which page the user was on when the back button was pressed. – h_k Aug 14 '14 at 19:43
  • That's a good approach @h_k – kakoma Aug 18 '14 at 06:35
  • Why does the method have to be `static`? Makes no sense. – IgorGanapolsky Oct 16 '15 at 14:25
  • 2
    I tested it without static modifier and worked. – Carlos Hernández Gil Jul 12 '16 at 18:39
  • @CarlosHernándezGil how could it be not static ? – user2396640 Dec 04 '17 at 13:56
  • anybody can able to resolve this : https://stackoverflow.com/questions/63760586/kotlin-handling-back-button-click-in-navigation-drawer-android ? – Jaimin Modi Sep 07 '20 at 14:04
15

 @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){

                    if (mDrawerLayout.isDrawerOpen(GravityCompat.START)){
                        mDrawerLayout.closeDrawer(GravityCompat.START);
                    }
                    return true;
                }

                return false;
            }
        });
    }

7

After looking at all solutions, I realised there is a much simpler solution.

In your activity's onBackPressed() that is hosting all your fragments, find the fragment that you want to prevent back press. Then if found, just return. Then popBackStack will never happen for this fragment.

  @Override
public void onBackPressed() {

        Fragment1 fragment1 = (Fragment1) getFragmentManager().findFragmentByTag(“Fragment1”);
        if (fragment1 != null)
            return;

        if (getFragmentManager().getBackStackEntryCount() > 0){
            getFragmentManager().popBackStack();

        }
}
Harry Aung
  • 1,602
  • 1
  • 14
  • 6
7

We created tiny library for handling back press across multiple fragments and/or in Activity. Usage is as simple as adding dependency in your gradle file:

compile 'net.skoumal.fragmentback:fragment-back:0.1.0'

Let your fragment implement BackFragment interface:

public abstract class MyFragment extends Fragment implements BackFragment {

    public boolean onBackPressed() {

        // -- your code --

        // return true if you want to consume back-pressed event
        return false;
    }

    public int getBackPriority() {
        return NORMAL_BACK_PRIORITY;
    }
}

Notify your fragments about back presses:

public class MainActivity extends AppCompatActivity {

    @Override
    public void onBackPressed() {
        // first ask your fragments to handle back-pressed event
        if(!BackFragmentHelper.fireOnBackPressedEvent(this)) {
            // lets do the default back action if fragments don't consume it
            super.onBackPressed();
        }
    }
}

For more details and other use-cases visit GitHub page:

https://github.com/skoumalcz/fragment-back

gingo
  • 3,149
  • 1
  • 23
  • 32
  • Thank you so much! I can say that this is the best way to handle back press in fragment. – Ray Li Sep 21 '18 at 22:20
  • Can anybody resolve this : https://stackoverflow.com/questions/63760586/kotlin-handling-back-button-click-in-navigation-drawer-android – Jaimin Modi Sep 07 '20 at 14:05
6

Or you could use getSupportFragmentManager().getBackStackEntryCount() to check what to do:

@Override
    public void onBackPressed() {

        logger.d("@@@@@@ back stack entry count : " + getSupportFragmentManager().getBackStackEntryCount());

        if (getSupportFragmentManager().getBackStackEntryCount() != 0) {

            // only show dialog while there's back stack entry
            dialog.show(getSupportFragmentManager(), "ConfirmDialogFragment");

        } else if (getSupportFragmentManager().getBackStackEntryCount() == 0) {

            // or just go back to main activity
            super.onBackPressed();
        }
    }
Padma Kumar
  • 19,893
  • 17
  • 73
  • 130
Robert
  • 1,660
  • 22
  • 39
6

If you manage the flow of adding to back stack every transaction, then you can do something like this in order to show the previous fragment when the user presses back button (you could map the home button too).

@Override
public void onBackPressed() {
    if (getFragmentManager().getBackStackEntryCount() > 0)
        getFragmentManager().popBackStack();
    else
        super.onBackPressed();
}
Joaquin Iurchuk
  • 5,499
  • 2
  • 48
  • 64
5

For Those Who Use Static Fragment

In a case if you have a static fragment then It would be preferable. Make an instance object of your fragment

private static MyFragment instance=null;

in onCreate() of MyFragment initialize that instance

  instance=this;

also make a function to get Instance

 public static MyFragment getInstance(){
   return instance;
}

also make functions

public boolean allowBackPressed(){
    if(allowBack==true){
        return true;
    }
    return false;
}


 //allowBack is a boolean variable that will be set to true at the action 
 //where you want that your backButton should not close activity. In my case I open 
 //Navigation Drawer then I set it to true. so when I press backbutton my 
 //drawer should be get closed

public void performSomeAction(){
    //.. Your code
    ///Here I have closed my drawer
}

In Your Activity You can do

@Override
public void onBackPressed() {

    if (MyFragment.getInstance().allowBackPressed()) { 
        MyFragment.getInstance().performSomeAction();
    }
    else{
        super.onBackPressed();
    }
}
Muhammad Adil
  • 4,358
  • 3
  • 32
  • 36
  • What if you have multiple fragments that use different back behavior? This won't work! – blueware Feb 28 '19 at 14:07
  • if you are saying that those back behaviour is gonna added inside the fragments, then you probably like to add different callbacks inside those fragments, and those callbacks will send back button pressed information to activity and from there activity can handle what should be done next. – Muhammad Adil Mar 12 '19 at 09:46
  • You'll need callbacks as the number of fragments that implement the back pressed behaviour which will result of unnecessary boilerplate code. That's the point – blueware Mar 12 '19 at 10:21
5

Working Code:

package com.example.keralapolice;

import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class ChiefFragment extends Fragment {
    View view;

    // public OnBackPressedListener onBackPressedListener;

    @Override
    public View onCreateView(LayoutInflater inflater,
            ViewGroup container, Bundle args) {

        view = inflater.inflate(R.layout.activity_chief, container, false);
        getActivity().getActionBar().hide();
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                Log.i(getTag(), "keyCode: " + keyCode);
                if (keyCode == KeyEvent.KEYCODE_BACK) {
                    getActivity().getActionBar().show();
                    Log.i(getTag(), "onKey Back listener is working!!!");
                    getFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                    // String cameback="CameBack";
                    Intent i = new Intent(getActivity(), home.class);
                    // i.putExtra("Comingback", cameback);
                    startActivity(i);
                    return true;
                } else {
                    return false;
                }
            }
        });
        return view;
    }
}
Edd
  • 3,724
  • 3
  • 26
  • 33
Android
  • 535
  • 5
  • 16
5

I think the easiest way is to create an interface, and in the Activity check if the fragment is of the interface type, and if so, call its method to handle the pop. Here's the interface to implement in the fragment.

public interface BackPressedFragment {

    // Note for this to work, name AND tag must be set anytime the fragment is added to back stack, e.g.
    // getActivity().getSupportFragmentManager().beginTransaction()
    //                .replace(R.id.fragment_container, MyFragment.newInstance(), "MY_FRAG_TAG")
    //                .addToBackStack("MY_FRAG_TAG")
    //                .commit();
    // This is really an override. Should call popBackStack itself.
    void onPopBackStack();
}

Here's how to implement it.

public class MyFragment extends Fragment implements BackPressedFragment
    @Override
    public void onPopBackStack() {
        /* Your code goes here, do anything you want. */
        getActivity().getSupportFragmentManager().popBackStack();
}

And in your Activity, when you handle the pop (likely in both onBackPressed and onOptionsItemSelected), pop the backstack using this method:

public void popBackStack() {
    FragmentManager fm = getSupportFragmentManager();
    // Call current fragment's onPopBackStack if it has one.
    String fragmentTag = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 1).getName();
    Fragment currentFragment = getSupportFragmentManager().findFragmentByTag(fragmentTag);
    if (currentFragment instanceof BackPressedFragment)
        ((BackPressedFragment)currentFragment).onPopBackStack();
    else
        fm.popBackStack();
}
Matt Koala
  • 2,171
  • 2
  • 18
  • 14
4

I'm working with SlidingMenu and Fragment, present my case here and hope helps somebody.

Logic when [Back] key pressed :

  1. When SlidingMenu shows, close it, no more things to do.
  2. Or when 2nd(or more) Fragment showing, slide back to previous Fragment, and no more things to do.
  3. SlidingMenu not shows, current Fragment is #0, do the original [Back] key does.

    public class Main extends SherlockFragmentActivity
    {
      private SlidingMenu menu=null;
      Constants.VP=new ViewPager(this);
    
      //Some stuff...
    
      @Override
      public void onBackPressed()
      {
        if(menu.isMenuShowing())
        {
          menu.showContent(true); //Close SlidingMenu when menu showing
          return;
        }
        else
        {
          int page=Constants.VP.getCurrentItem();
          if(page>0)
          {
            Constants.VP.setCurrentItem(page-1, true); //Show previous fragment until Fragment#0
            return;
          }
          else
          {super.onBackPressed();} //If SlidingMenu is not showing and current Fragment is #0, do the original [Back] key does. In my case is exit from APP
        }
      }
    }
    
RRTW
  • 3,160
  • 1
  • 35
  • 54
4

This is a very good and reliable solution: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

The guy has made an abstract fragment that handles the backPress behaviour and is switching between the active fragments using the strategy pattern.

For some of you there maybe a little drawback in the abstract class...

Shortly, the solution from the link goes like this:

// Abstract Fragment handling the back presses

public abstract class BackHandledFragment extends Fragment {
    protected BackHandlerInterface backHandlerInterface;
    public abstract String getTagText();
    public abstract boolean onBackPressed();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(!(getActivity()  instanceof BackHandlerInterface)) {
            throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
        } else {
            backHandlerInterface = (BackHandlerInterface) getActivity();
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        // Mark this fragment as the selected Fragment.
        backHandlerInterface.setSelectedFragment(this);
    }

    public interface BackHandlerInterface {
        public void setSelectedFragment(BackHandledFragment backHandledFragment);
    }
}   

And usage in the activity:

// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS 
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment

public class TheActivity extends FragmentActivity implements BackHandlerInterface {
    private BackHandledFragment selectedFragment;

    @Override
    public void onBackPressed() {
        if(selectedFragment == null || !selectedFragment.onBackPressed()) {
            // Selected fragment did not consume the back press event.
            super.onBackPressed();
        }
    }

    @Override
    public void setSelectedFragment(BackHandledFragment selectedFragment) {
        this.selectedFragment = selectedFragment;
    }
}
Amio.io
  • 20,677
  • 15
  • 82
  • 117
4
            rootView.setFocusableInTouchMode(true);
            rootView.requestFocus();
            rootView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event)   {
            if (keyCode == KeyEvent.KEYCODE_BACK) {


                Fragment NameofFragment = new NameofFragment;

                FragmentTransaction  transaction=getFragmentManager().beginTransaction();
                transaction.replace(R.id.frame_container,NameofFragment);

                transaction.commit();

                return true;
            }
            return false;
        }
    });

    return rootView;
Ashish Soni
  • 286
  • 3
  • 4
2

Add addToBackStack() to fragment transaction and then use below code for Implementing Back Navigation for Fragments

getSupportFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() {
        public void onBackStackChanged() {
            // Update your UI here.
        }
    });
Lalit Sharma
  • 1,142
  • 1
  • 15
  • 32
  • It won't let you to actually override behavior on back stack change. Fragment will be popped out of the back stack and you won't be able to prevent it. – Dmitry Zaytsev Aug 13 '14 at 14:14
2

if you are using FragmentActivity. then do like this

first call This inside your Fragment.

public void callParentMethod(){
    getActivity().onBackPressed();
}

and then Call onBackPressed method in side your parent FragmentActivity class.

@Override
public void onBackPressed() {
  //super.onBackPressed();
  //create a dialog to ask yes no question whether or not the user wants to exit
  ...
}
hash
  • 5,336
  • 7
  • 36
  • 59
2

You can use from getActionBar().setDisplayHomeAsUpEnabled() :

@Override
public void onBackStackChanged() {
    int backStackEntryCount = getFragmentManager().getBackStackEntryCount();

    if(backStackEntryCount > 0){
        getActionBar().setDisplayHomeAsUpEnabled(true);
    }else{
        getActionBar().setDisplayHomeAsUpEnabled(false);
    }
}
1

Add this code in your Activity

@Override

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

And add this line in your Fragment before commit()

ft.addToBackStack("Any name");

Ravi
  • 281
  • 2
  • 4
1

in fragment class put this code for back event:

 rootView.setFocusableInTouchMode(true);
        rootView.requestFocus();
        rootView.setOnKeyListener( new OnKeyListener()
        {
            @Override
            public boolean onKey( View v, int keyCode, KeyEvent event )
            {
                if( keyCode == KeyEvent.KEYCODE_BACK )
                {
                    FragmentManager fragmentManager = getFragmentManager();
                    fragmentManager.beginTransaction()
                            .replace(R.id.frame_container, new Book_service_provider()).commit();

                    return true;
                }
                return false;
            }
        } );
tej shah
  • 2,995
  • 2
  • 25
  • 35
0

Checking the backstack works perfectly


@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
    if (keyCode == KeyEvent.KEYCODE_BACK)
    {
        if (getFragmentManager().getBackStackEntryCount() == 1)
        {
            // DO something here since there is only one fragment left
            // Popping a dialog asking to quit the application
            return false;
        }
    }
    return super.onKeyDown(keyCode, event);
}
Devrath
  • 42,072
  • 54
  • 195
  • 297
-2

In your oncreateView() method you need to write this code and in KEYCODE_BACk condition you can write whatever the functionality you want

View v = inflater.inflate(R.layout.xyz, container, false);
//Back pressed Logic for fragment 
v.setFocusableInTouchMode(true); 
v.requestFocus(); 
v.setOnKeyListener(new View.OnKeyListener() { 
    @Override 
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                getActivity().finish(); 
                Intent intent = new Intent(getActivity(), MainActivity.class);
                startActivity(intent);

                return true; 
            } 
        } 
        return false; 
    } 
}); 
Raj Kumar
  • 688
  • 8
  • 18