Search code examples
androidxonbackpressed

Androidx OnBackPressedDispatcher - how to consume the back button press


I would like the onBackPressedDispatcher to absorb the back button press event. Sometimes but I don't see an option for it. Whats happening is that we are just today trying to upgrade to onBackPressedDispatcher in androidX but we have already overridden onBackPressd in activity. so when our onBackPressedDispatcher calls OnBackPressedCallback afterwards there is also a call to activities onBackPressed override. we don't want that. the onBackpressed should be consumed on the spot. here is what I have so far:

const val TAG = "MyTag"

class MyActivity : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_first)
        MyTester(this)
    }

    override fun onBackPressed() {
        super.onBackPressed()
        Log.v(TAG, "Activities class back button Pressed")

    }

    inner class MyTester(var activity: AppCompatActivity) {
        init {
            addBackCB()
        }

        fun addBackCB() {
            var callback = object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    Log.v(TAG, "inner class MyTester back button")
                }
            }
            activity.onBackPressedDispatcher.addCallback(activity, callback);
        }
    }
}

Which prints the following:

V/MyTag: inner class MyTester back button
V/MyTag: Activities class back button Pressed

If I don't call super.onBackPressed() then the dispatcher does not even work. it needs that call.


Solution

  • This is because the OnBackPressedDispatcher is called in ComponentActivity.onBackPressed(), if you look at the source code:

        @Override
        @MainThread
        public void onBackPressed() {
            mOnBackPressedDispatcher.onBackPressed();
        }
    

    So you'll never reach your callback if you override onBackPressed and never call the super method. I think the whole idea behind OnBackPressedDispatcher is that you shouldn't have to override Activity.onBackPressed if you want your fragments to intercept back presses. This is mentioned in one of the guides.

    If you really want your activity to handle the back press, you can try something like this in your override:

        if (onBackPressedDispatcher.hasEnabledCallbacks()) {
          // There's an active callback; let the fragment handle it
          super.onBackPressed()
        } else {
          // Do your activity's back press handling here
        }
    

    Be careful doing this, though. After trying it myself, you might find that hasEnabledCallbacks will return true even when you haven't added any callbacks yourself. This is because your FragmentManager has its own back press callback that's going to be enabled whenever backStackEntryCount > 0. I'm not sure if there's a quick workaround for that.