ChatGPT解决这个技术问题 Extra ChatGPT

How to implement onBackPressed() in Fragments?

Is there a way in which we can implement onBackPressed() in Android Fragment similar to the way in which we implement in Android Activity?

As the Fragment lifecycle do not have onBackPressed(). Is there any other alternative method to over ride onBackPressed() in Android 3.0 fragments?

IMHO, a fragment should neither know nor care about the BACK button. An activity could care about the BACK button, though with fragments that is normally handled by FragmentManager. But since the fragment does not know about its larger environment (e.g., whether or not it is one of several in the activity), it is not really safe for a fragment to be trying to determine what proper BACK functionality is.
How about when all the fragment does it to display a WebView, and you want the WebView to "go back" to the previous page when the back button is pressed?
Michael Herbig answer was perfect for me. But for those who cant use getSupportFragmentManager(). Use getFragmentManager() instead.
to answer mharper may be you can do something like webview.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && webview.canGoBack()) { webview.goBack(); return true; } return false; } });
Hi, there is a much much better and cleaner approach. Also documented by the official documentation: developer.android.com/guide/navigation/navigation-custom-back

R
Rajat Mittal

I solved in this way override onBackPressed in the Activity. All the FragmentTransaction are addToBackStack before commit:

@Override
public void onBackPressed() {

    int count = getSupportFragmentManager().getBackStackEntryCount();

    if (count == 0) {
        super.onBackPressed();
        //additional code
    } else {
        getSupportFragmentManager().popBackStack();
    }

}

count == 1 will allow to close the first fragment on single back button press. But otherwise the best solution
If you're using the support v7 library and your Activity extends from FragmentActivity (or a subclass, such as AppCompatActivity) this will happen by default. See FragmentActivity#onBackPressed
but you can't use variables, classes & functions from fragment's class in this code
@Prabs if you are using support v4 fragment then make sure you are using getSupportFragmentManager().getBackStackEntryCount();
B
BierDav

In my opinion the best solution is:

JAVA SOLUTION

Create simple interface :

public interface IOnBackPressed {
    /**
     * If you return true the back press will not be taken into account, otherwise the activity will act naturally
     * @return true if your processing has priority if not false
     */
    boolean onBackPressed();
}

And in your Activity

public class MyActivity extends Activity {
    @Override public void onBackPressed() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_container);
       if (!(fragment instanceof IOnBackPressed) || !((IOnBackPressed) fragment).onBackPressed()) {
          super.onBackPressed();
       }
    } ...
}

Finally in your Fragment:

public class MyFragment extends Fragment implements IOnBackPressed{
   @Override
   public boolean onBackPressed() {
       if (myCondition) {
            //action not popBackStack
            return true; 
        } else {
            return false;
        }
    }
}

KOTLIN SOLUTION

1 - Create Interface

interface IOnBackPressed {
    fun onBackPressed(): Boolean
}

2 - Prepare your Activity

class MyActivity : AppCompatActivity() {
    override fun onBackPressed() {
        val fragment =
            this.supportFragmentManager.findFragmentById(R.id.main_container)
        (fragment as? IOnBackPressed)?.onBackPressed()?.not()?.let {
            super.onBackPressed()
        }
    }
}

3 - Implement in your target Fragment

class MyFragment : Fragment(), IOnBackPressed {
    override fun onBackPressed(): Boolean {
        return if (myCondition) {
            //action not popBackStack
            true
        } else {
            false
        }
    }
}

What is R.id.main_container? Is that the ID for the FragmentPager?
I answered my own question by testing, it is the FragmentPager's ID.
Shouldn't it be .onBackPressed()?.takeIf { !it }?.let{...}? .not() just returns the inverse.
val fragment = this.supportFragmentManager.findFragmentById(R.id.flContainer) as? NavHostFragment val currentFragment = fragment?.childFragmentManager?.fragments?.get(0) as? IOnBackPressed currentFragment?.onBackPressed()?.takeIf { !it }?.let{ super.onBackPressed() } This is for people who use Kotlin and NavigationController
If you don't want to implement it for all the fragments in the activity. override fun onBackPressed() { val fragment = this.supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment val currentFragment = fragment?.childFragmentManager?.fragments?.get(0) as? FragmentOnBackPressListener if (currentFragment != null) { currentFragment.onBackPressed().takeIf { !it }?.let { super.onBackPressed() } } else { super.onBackPressed() } }
O
Oderik

If you're using androidx.appcompat:appcompat:1.1.0 or above then you can add an OnBackPressedCallback to your fragment as follows

requireActivity()
    .onBackPressedDispatcher
    .addCallback(this, object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            Log.d(TAG, "Fragment back pressed invoked")
            // Do custom work here    

            // if you want onBackPressed() to be called as normal afterwards
            if (isEnabled) {
                isEnabled = false
                requireActivity().onBackPressed()
            }
        }
    }
)

See https://developer.android.com/guide/navigation/navigation-custom-back


If you are using androidx-core-ktx, you can use requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { /* code to be executed when back is pressed */ }
It's important to note that the LifecycleOwner param should be added as in this example. Without it, any fragments started afterwards will call handleBackPressed() if the back button is pressed.
is this method must with the navigation library?
That's what i'm talking about!! So many ancient answers that make me go "you're kidding me right?" now that google recommends fragments over activities.
change "this" for "viewLifecycleOwner" for the first param of addCallback method and you are done! This way you dont have to be worried about unregister the callback cause the callback would be attached to the activity lifecycle.
V
Vasily Kabunov

According to @HaMMeRed answer here is pseudocode how should it works. Lets say that your main activity is called BaseActivity which has child fragments (like in SlidingMenu lib example). Here are the steps:

First we need create interface and class which implements its interface to have generic method

Create class interface OnBackPressedListener public interface OnBackPressedListener { public void doBack(); } Create class which implements skills of OnBackPressedListener public class BaseBackPressedListener implements OnBackPressedListener { private final FragmentActivity activity; public BaseBackPressedListener(FragmentActivity activity) { this.activity = activity; } @Override public void doBack() { activity.getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); } } Since now, we will work on our code BaseActivity and its fragments Create private listener on top of your class BaseActivity protected OnBackPressedListener onBackPressedListener; create method to set listener in BaseActivity public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) { this.onBackPressedListener = onBackPressedListener; } in override onBackPressed implement something like that @Override public void onBackPressed() { if (onBackPressedListener != null) onBackPressedListener.doBack(); else super.onBackPressed(); in your fragment in onCreateView you should add our listener @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { activity = getActivity(); ((BaseActivity)activity).setOnBackPressedListener(new BaseBackPressedListener(activity)); View view = ... ; //stuff with view return view; }

Voila, now when you click back in fragment you should catch your custom on back method.


If more than one fragment is a listener, how do you determine, in onBackPressed(), which fragment was being displayed when the back button was pressed?
you can customize click listener instead new baseBackPressedListener and call there as anonymous to set own behaviuor, something like this: ((BaseActivity)activity).setOnBackPressedListener(new OnBackpressedListener(){ public void doBack() { //...your stuff here }});
Thanks, I have changed my position on this though, I'd recommend decoupling with local broadcast messages now though. I think it would yield higher quality components that are highly decoupled.
This worked perfectly for me, I do restart the Activity
C
Community

This worked for me: https://stackoverflow.com/a/27145007/3934111

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

    if(getView() == null){
        return;
    }

    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){
                // handle back button's click listener
                return true;
            }
            return false;
        }
    });
}

Worked flawlessly! But then you also have to handle the default action, by writing one more IF condition probably. Since, I was lowering down my slideUpPanel if it was Expanded. So, I first had to mark a check if(panel is up) then.....
The problem with this solution is that the getView() returns only the main view (and not the subview, if they gain focus). So if you have an EditText and type some text then press "back" once to hide the keyboard, the second press on "back" is initiated from the "EditText" (a view itself) and this method does not seem to catch the "back" button press then (since it is only catching for the main view). As I understand it, you could catch the keypress events on your "EditText" as well as any other views, but if you have a "complex" form then this isn't as clean and maintainable as it could be.
This is a great simple solution for the nightmare that is fragments. If you have a 'complex' edittext form then you should probably delete your project and start over. Return false when you want to use the standard behaviour. Return true when you have intercepted the back press and have done something with it
has some minuses, but still NICE solution.
V
Vasily Kabunov

If you wanted that sort of functionality you would need to override it in your activity, and then add a YourBackPressed interface to all your fragments, which you call on the relevant fragment whenever the back button is pressed.

Edit: I'd like to append my previous answer.

If I were to do this today, I'd use a broadcast, or possibly a ordered broadcast if I expected other panels to update in unison to the master/main content panel.

LocalBroadcastManager in the Support Library can help with this, and you just send the broadcast in onBackPressed and subscribe in your fragments that care. I think that Messaging is a more decoupled implementation and would scale better, so it would be my official implementation recommendation now. Just use the Intent's action as a filter for your message. send your newly created ACTION_BACK_PRESSED, send it from your activity and listen for it in the relevant fragments.


Pretty nifty idea! some additional thoughts: + it's important to realize this logic with the broadcast going from activity > fragments (not the other way round). OnBackPressed is only available at the activity level, so trapping the event there and broadcasting it to all "listening" fragments is key here. + Using an EventBus (like Square's Otto) makes the implementation for a case like this trivial!
I haven't used Square's EventBus yet, but I will be in future products. I think it's a better pure-java solution, and if you can knock the Android out sections of your architecture, all the better.
How do you let only the top fragments to handle the event? for example, you would want to destroy the currently showing fragment
The broadcast receiver should be bound to the life cycle if you are using that, so when it's not visible it shouldn't receive the event.
Also note that LocalBroadcastManager can't do ordered broadcasts
S
Sterling Diaz

None of that is easy to implement nor will it function in an optimal way.

Fragments have a method call onDetach that will do the job.

@Override
    public void onDetach() {
        super.onDetach();
        PUT YOUR CODE HERE
    }

THIS WILL DO THE JOB.


but the issue here is that you do not know whether the fragment was detached due to a back press or due to some other action, which the led the user go so some other activity or fragment.
onDetach() is called when the fragment is no longer attached to its activity. This is called after onDestroy(). Although you would get to this code when you press the back button you would also get this code when you change from fragment to fragment. You could do something nifty to make this work though...
Works fine for a DialogFragment.
Don't forget to add isRemoving() as described in stackoverflow.com/a/27103891/2914140.
this is wrong. It can be called for several reasons
A
Amjad Alwareh

Google has released a new API to deal with onBackPressed in Fragment:

activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {

            }
        })

This is the real answer on these days.
How to call a super.onBackPressed in this approach?
this post explains it better medium.com/@debuggingisfun/…
R
Rudi

Just add addToBackStack while you are transitioning between your fragments like below:

fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();

if you write addToBackStack(null) , it will handle it by itself but if you give a tag , you should handle it manually.


Is there anything else that needs to be done or does adding the addToBackStack method is sufficient?
if you just add that it should works, if it still not working there should be something in your code. Leave the code somewhere to see please @SreecharanDesabattula
Best answer. Day saved!
S
Sanjay Joshi

New and better approach: Following piece of code in a Fragment will help you to capture the back-press event.

JAVA

@Override
public void onAttach(@NonNull Context context) {
    super.onAttach(context);

    OnBackPressedCallback callback = new OnBackPressedCallback(true) {
        @Override
        public void handleOnBackPressed() {
            Toast.makeText(mContext, "back pressed", Toast.LENGTH_SHORT).show();
            
            // And when you want to go back based on your condition
            if (yourCondition) {
                this.setEnabled(false);
                requireActivity().onBackPressed();
            }
        }
    };

    requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}

Kotlin

activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {

    }
})

B
B-GangsteR

Using Navigation component you can do it like this:

Java

public class MyFragment extends Fragment {

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // This callback will only be called when MyFragment is at least Started.
    OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
        @Override
        public void handleOnBackPressed() {
            // Handle the back button event
        }
    });
    requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);

    // The callback can be enabled or disabled here or in handleOnBackPressed()
}
...
}

Kotlin

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
}
...
}

easiest method to do it
C
Community

since this question and some of the answers are over five years old, let me share my solution. This is a follow-up and modernization to the answer from @oyenigun

UPDATE: At the bottom of this article, I added an alternative implementation using an abstract Fragment extension that won't involve the Activity at all, which would be useful for anyone with a more complex fragment hierarchy involving nested fragments that require different back behavior.

I needed to implement this because some of the fragments I use have smaller views that I would like to dismiss with the back button, such as small information views that pop up, etc, but this is good for anyone who needs to override the behavior of the back button inside fragments.

First, define an Interface

public interface Backable {
    boolean onBackPressed();
}

This interface, which I call Backable (I'm a stickler for naming conventions), has a single method onBackPressed() that must return a boolean value. We need to enforce a boolean value because we will need to know if the back button press has "absorbed" the back event. Returning true means that it has, and no further action is needed, otherwise, false says that the default back action still must take place. This interface should be it's own file (preferably in a separate package named interfaces). Remember, separating your classes into packages is good practice.

Second, find the top fragment

I created a method that returns the last Fragment object in the back stack. I use tags... if you use ID's, make the necessary changes. I have this static method in a utility class that deals with navigation states, etc... but of course, put it where it best suits you. For edification, I've put mine in a class called NavUtils.

public static Fragment getCurrentFragment(Activity activity) {
    FragmentManager fragmentManager = activity.getFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 0) {
        String lastFragmentName = fragmentManager.getBackStackEntryAt(
                fragmentManager.getBackStackEntryCount() - 1).getName();
        return fragmentManager.findFragmentByTag(lastFragmentName);
    }
    return null;
}

Make sure the back stack count is greater than 0, otherwise an ArrayOutOfBoundsException could be thrown at runtime. If it isn't greater than 0, return null. We'll check for a null value later...

Third, Implement in a Fragment

Implement the Backable interface in whichever fragment where you need to override the back button behavior. Add the implementation method.

public class SomeFragment extends Fragment implements 
        FragmentManager.OnBackStackChangedListener, Backable {

...

    @Override
    public boolean onBackPressed() {

        // Logic here...
        if (backButtonShouldNotGoBack) {
            whateverMethodYouNeed();
            return true;
        }
        return false;
    }

}

In the onBackPressed() override, put whatever logic you need. If you want the back button to not pop the back stack (the default behavior), return true, that your back event has been absorbed. Otherwise, return false.

Lastly, in your Activity...

Override the onBackPressed() method and add this logic to it:

@Override
public void onBackPressed() {

    // Get the current fragment using the method from the second step above...
    Fragment currentFragment = NavUtils.getCurrentFragment(this);

    // Determine whether or not this fragment implements Backable
    // Do a null check just to be safe
    if (currentFragment != null && currentFragment instanceof Backable) {

        if (((Backable) currentFragment).onBackPressed()) {
            // If the onBackPressed override in your fragment 
            // did absorb the back event (returned true), return
            return;
        } else {
            // Otherwise, call the super method for the default behavior
            super.onBackPressed();
        }
    }

    // Any other logic needed...
    // call super method to be sure the back button does its thing...
    super.onBackPressed();
}

We get the current fragment in the back stack, then we do a null check and determine if it implements our Backable interface. If it does, determine if the event was absorbed. If so, we're done with onBackPressed() and can return. Otherwise, treat it as a normal back press and call the super method.

Second Option to not involve the Activity

At times, you don't want the Activity to handle this at all, and you need to handle it directly within the fragment. But who says you can't have Fragments with a back press API? Just extend your fragment to a new class.

Create an abstract class that extends Fragment and implements the View.OnKeyListner interface...

import android.app.Fragment;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;

public abstract class BackableFragment extends Fragment implements View.OnKeyListener {

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        view.setFocusableInTouchMode(true);
        view.requestFocus();
        view.setOnKeyListener(this);
    }

    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_BACK) {
                onBackButtonPressed();
                return true;
            }
        }

        return false;
    }

    public abstract void onBackButtonPressed();
}

As you can see, any fragment that extends BackableFragment will automatically capture back clicks using the View.OnKeyListener interface. Just call the abstract onBackButtonPressed() method from within the implemented onKey() method using the standard logic to discern a back button press. If you need to register key clicks other than the back button, just be sure to call the super method when overriding onKey() in your fragment, otherwise you'll override the behavior in the abstraction.

Simple to use, just extend and implement:

public class FragmentChannels extends BackableFragment {

    ...

    @Override
    public void onBackButtonPressed() {
        if (doTheThingRequiringBackButtonOverride) {
            // do the thing
        } else {
            getActivity().onBackPressed();
        }
    }

    ...
}

Since the onBackButtonPressed() method in the super class is abstract, once you extend you must implement onBackButtonPressed(). It returns void because it just needs to perform an action within the fragment class, and does not need to relay the absorption of the press back to the Activity. Make sure you do call the Activity onBackPressed() method if whatever you're doing with the back button doesn't require handling, otherwise, the back button will be disabled... and you don't want that!

Caveats As you can see, this sets the key listener to the root view of the fragment, and we'll need to focus it. If there are edit texts involved (or any other focus-stealing views) in your fragment that extends this class, (or other inner fragments or views that have the same), you'll need to handle that separately. There's a good article on extending an EditText to lose focus on a back press.

I hope someone finds this useful. Happy coding.


Thanks, it's a nice solution. Can you say, why do you call super.onBackPressed(); twice?
It's only called once per scenario regarding the null state of currentFragment. If the fragment is not null and the fragment implements the Backable interface, no action is taken. If the fragment is not null and it does NOT implement Backable, we call the super method. If the fragment is null, it skips to the last super call.
Sorry, I didn't understand. In the case when a currentFragment is not null and is an instance of Backable and it is detached (we pressed back button and close the fragment) the first occurence of super.onBackPressed(); is called, then the second one.
Excellent Solution
Just a sidenote. instanceof implicitly does a null check, so no need to explicitly check for null prior to that
R
Ryan M

The solution is simple:

If you have a base fragment class that all fragments extend, then add this code to it's class, otherwise create such a base fragment class

/* 
* called when on back pressed to the current fragment that is returned
*/
public void onBackPressed()
{
    // add code in super class when override
}

In your Activity class, override onBackPressed as follows:

private BaseFragment _currentFragment;

@Override
public void onBackPressed()
{
      super.onBackPressed();
     _currentFragment.onBackPressed();
}

In your Fragment class, add your desired code:

@Override
public void onBackPressed()
{
    setUpTitle();
}

V
V-rund Puro-hit

onBackPressed() cause Fragment to be detach from Activity.

According to @Sterling Diaz answer I think he is right. BUT some situation will be wrong. (ex. Rotate Screen)

So, I think we could detect whether isRemoving() to achieve goals.

You can write it at onDetach() or onDestroyView(). It is work.

@Override
public void onDetach() {
    super.onDetach();
    if(isRemoving()){
        // onBackPressed()
    }
}

@Override
public void onDestroyView() {
    super.onDestroyView();
    if(isRemoving()){
        // onBackPressed()
    }
}

o
oyenigun

You should add interface to your project like below;

public interface OnBackPressed {

     void onBackPressed();
}

And then, you should implement this interface on your fragment;

public class SampleFragment extends Fragment implements OnBackPressed {

    @Override
    public void onBackPressed() {
        //on Back Pressed
    }

}

And you can trigger this onBackPressed event under your activities onBackPressed event like below;

public class MainActivity extends AppCompatActivity {
       @Override
        public void onBackPressed() {
                Fragment currentFragment = getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getBackStackEntryCount() - 1);
                if (currentFragment instanceof OnBackPressed) {  
                    ((OnBackPressed) currentFragment).onBackPressed();
                }
                super.onBackPressed();
        }
}

It's agood method, but be careful, don't call getActivity().onBackPressed(); as it will invoke exception: "java.lang.StackOverflowError: stack size 8MB".
D
David Elmasllari

Inside the fragment's onCreate method add the following:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    OnBackPressedCallback callback = new OnBackPressedCallback(true) {
        @Override
        public void handleOnBackPressed() {
            //Handle the back pressed
        }
    };
    requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}

after adding this myFragment backpress works but now activity backpress didnt
Inside the callback you can handle the activities back pressed. 'handleOnBackPressed() { //Handle the back pressed requireActivity().onBackPressed(); } ' @SunilChaudhary
You can even remove the callback using callback.remove() if the activity's back pressed needs to be called.
A
Akshat

If you use EventBus, it is probably a far more simpler solution :

In your Fragment :

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    EventBus.getDefault().register(this);
}

@Override
public void onDetach() {
    super.onDetach();
    EventBus.getDefault().unregister(this);
}


// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    getSupportFragmentManager().popBackStack();
}

and in your Activity class you can define :

@Override
public void onStart() {
    super.onStart();
    EventBus.getDefault().register(this);
}

@Override
public void onStop() {
    EventBus.getDefault().unregister(this);
    super.onStop();
}

// This method will be called when a MessageEvent is posted
public void onEvent(BackPressedMessage type){
    super.onBackPressed();
}

@Override
public void onBackPressed() {
    EventBus.getDefault().post(new BackPressedMessage(true));
}

BackPressedMessage.java is just a POJO object

This is super clean and there is no interface/implementation hassle.


l
lukassos

Well I done it like this, and it work for me

Simple interface

FragmentOnBackClickInterface.java

public interface FragmentOnBackClickInterface {
    void onClick();
}

Example implementation

MyFragment.java

public class MyFragment extends Fragment implements FragmentOnBackClickInterface {

// other stuff

public void onClick() {
       // what you want to call onBackPressed?
}

then just override onBackPressed in activity

    @Override
public void onBackPressed() {
    int count = getSupportFragmentManager().getBackStackEntryCount();
    List<Fragment> frags = getSupportFragmentManager().getFragments();
    Fragment lastFrag = getLastNotNull(frags);
    //nothing else in back stack || nothing in back stack is instance of our interface
    if (count == 0 || !(lastFrag instanceof FragmentOnBackClickInterface)) {
        super.onBackPressed();
    } else {
        ((FragmentOnBackClickInterface) lastFrag).onClick();
    }
}

private Fragment getLastNotNull(List<Fragment> list){
    for (int i= list.size()-1;i>=0;i--){
        Fragment frag = list.get(i);
        if (frag != null){
            return frag;
        }
    }
    return null;
}

Not working ! super.onbackpressed() gets called always :(
How to pass this event Inner Fragment. I have ViewPager in Activity and that ViewPager has Fragments, Now all those Fragment have child fragment. How to pass back button event to that child fragments.
@KishanVaghela well I didn't touched android since then but I have one idea. Give me 24th to update my answer.
Ok no problem, One option is that I need to pass listener event to every child fragment from parent fragment. but It's not an ideal way because I need to do this for every fragments.
@KishanVaghela I was thinking about manager in activity. You could add/remove fragments with that interface. But with this approach you have to implement manager in every fragment that have subfragments. So maybe better solution will be creating manager as singleton. Then you will have to add/remove fragments/objects and in 'onBackPressed' you call method 'onBackPressed' of this manager. That method will call method 'onClick' in every object that was added to manager. Is that more or less clear to you?
H
Hamidreza Samadi

this is my solution:

in MyActivity.java:

public interface OnBackClickListener {
        boolean onBackClick();
    }

    private OnBackClickListener onBackClickListener;

public void setOnBackClickListener(OnBackClickListener onBackClickListener) {
        this.onBackClickListener = onBackClickListener;
    }

@Override
    public void onBackPressed() {
        if (onBackClickListener != null && onBackClickListener.onBackClick()) {
            return;
        }
        super.onBackPressed();
    }

and in Fragment:

((MyActivity) getActivity()).setOnBackClickListener(new MyActivity.OnBackClickListener() {
    @Override
    public boolean onBackClick() {
        if (condition) {
            return false;
        }

        // some codes

        return true;
    }
});

p
protanvir993

In kotlin, it's way simplier.

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            //
        }
    })
}

this one of the best solution for kotlin developers . Thanks man.
V
Vadim Kotov
public class MyActivity extends Activity {

    protected OnBackPressedListener onBackPressedListener;

    public interface OnBackPressedListener {
        void doBack();
    }

    public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
        this.onBackPressedListener = onBackPressedListener;
    }

    @Override
    public void onBackPressed() {
        if (onBackPressedListener != null)
            onBackPressedListener.doBack();
        else
            super.onBackPressed();
    } 

    @Override
    protected void onDestroy() {
        onBackPressedListener = null;
        super.onDestroy();
    }
}

in your fragment add the following, dont forget to implement mainactivity's interface.

public class MyFragment extends Framgent implements MyActivity.OnBackPressedListener {
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
         ((MyActivity) getActivity()).setOnBackPressedListener(this);
    }

@Override
public void doBack() {
    //BackPressed in activity will call this;
}

}

S
Shahid Sarwar

This is just a small code that will do the trick:

 getActivity().onBackPressed();

Hope it helps someone :)


He asked to override the behavior, not to simply invoke the activity method.
I did read it carefully, thanks. Your solution simply relays the onBackPressed method back to the Activity, when he asked how to override.
t
tomrozb

You can use onBackPressedDispatcher of parent activity like this:

val backpress = requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, true) {
            // here dispatcher works for any action when back pressed
}

you can also enable/disable backpress button from fragment any time like this:

backpress.isEnabled = true/false

A
Ayush Sth
 requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
        //your code 
    }

M
Max
@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) {
                // handle back button
                replaceFragmentToBackStack(getActivity(), WelcomeFragment.newInstance(bundle), tags);

                return true;
            }

            return false;
        }
    });
}

Only if do not fragments have a focusable view (such as edit text), let fragments handle back button itself as this answer does. Otherwise, let activity containing fragments do it by OnBackPress() as the first answer is written; since focusable view will steal fragment's focus. However, we can regain focus for fragment by clear focus all focusable views by clearFocus() method and re-focus to fragment.
T
The Finest Artist

How about using onDestroyView()?

@Override
public void onDestroyView() {
    super.onDestroyView();
}

what about going to another fragment from actual fragment, what will happen using your method? :)
Most useless answer. It is the same as writing i = i or if (1 < 0) {}.
V
V-rund Puro-hit

Just follow these steps:

Always while adding a fragment,

fragmentTransaction.add(R.id.fragment_container, detail_fragment, "Fragment_tag").addToBackStack(null).commit();

Then in the main activity, override onBackPressed()

if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
    getSupportFragmentManager().popBackStack();
} else {
    finish();
}

To handle the back button in your app,

Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag("Fragment_tag");
if (f instanceof FragmentName) {
    if (f != null) 
        getActivity().getSupportFragmentManager().beginTransaction().remove(f).commit()               
}

That's it!


P
Parsania Hardik

Very short and sweet answer:

getActivity().onBackPressed();

Explanation of whole scenario of my case:

I have FragmentA in MainActivity, I am opening FragmentB from FragmentA (FragmentB is child or nested fragment of FragmentA)

 Fragment duedateFrag = new FragmentB();
 FragmentTransaction ft  = getFragmentManager().beginTransaction();
 ft.replace(R.id.container_body, duedateFrag);
 ft.addToBackStack(null);
 ft.commit();

Now if you want to go to FragmentA from FragmentB you can simply put getActivity().onBackPressed(); in FragmentB.


OP has asked about how to handle back press I guess
Also whoever downvoted doesn't think you addressed the problem rightly and it's his right you are on a public forum and no one has obligation to upvote you or think you are correct , go to Meta and appeal if you think it's wrong . Learn to behave in public forums dude.
@user31231234124 some persons told me that this answer is not related to question....if you think this answer will help other visitors in future to implement onbackpressed() in fragment in easiest way, please upvote my answer so that more users can get benefit..........
some people are blind and dumb enough to realise the perfection in your answer... just ignore those kiddos/scrip kiddies... it has solved my problem 100% percent... Thanks a lot...
T
TonnyL

According to the AndroidX release notes, androidx.activity 1.0.0-alpha01 is released and introduces ComponentActivity, a new base class of the existing FragmentActivity and AppCompatActivity. And this release brings us a new feature:

You can now register an OnBackPressedCallback via addOnBackPressedCallback to receive onBackPressed() callbacks without needing to override the method in your activity.


Can you show an example of this? I'm not getting that method to resolve.
@BryanBryce I haven't find an example but the official doc: developer.android.com/reference/androidx/activity/…
The method won't resolve b/c AppCompatActivity is actually extending from androidx.core.app.ComponentActivity instead of androidx.activity.ComponentActivity.
k
krishnakumarcn

Providing custom back navigation by handling onBackPressed is now more easy with callbacks inside the fragment.

class MyFragment : Fragment() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val onBackPressedCallback = object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (true == conditionForCustomAction) {
                    myCustomActionHere()
                } else  NavHostFragment.findNavController(this@MyFragment).navigateUp();    
        }
    }
    requireActivity().onBackPressedDispatcher.addCallback(
        this, onBackPressedCallback
    )
    ...
}

If you want the default back action based on some condition, you can use:

 NavHostFragment.findNavController(this@MyFragment).navigateUp();