Since the old Activity.onBackPressed()
becomes deprecated starting Android 33, what is the better way to call it programmatically?
Example:
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
// Handle default back arrow click
android.R.id.home -> {
onBackPressed()
}
...
We could create and add OnBackPressedCallback
to the onBackPressedDispatcher
like this.
onBackPressedDispatcher.addCallback(
this, // Lifecycle owner
backPressedCallback
)
private val backPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (viewPager.currentItem != 0)
viewPager.setCurrentItem(0, true)
else
finish()
}
}
Then replace the old onBackPressed
with
// Handle default back arrow click
android.R.id.home -> {
backPressedCallback.handleOnBackPressed()
}
But I saw this public method in onBackPressedDispatcher
and wondering if I could use it instead.
onBackPressedDispatcher.onBackPressed()
Does this method iterates on each OnBackPressedCallback
that has been added in the onBackPressedDispatcher
?
So basically onBackPressedDispatcher.onBackPressed()
is the same as Activity.onBackPressed()
and you can use it in the same manner if you don't care about precise navigation. How do I know that? - well, you can see the source code of the ComponentActivity
(basically a parent of a regular Activity you are using), and its onBackPressed()
looks like this:
@Override
@MainThread
public void onBackPressed() {
mOnBackPressedDispatcher.onBackPressed();
}
Regarding it calling over the callbacks queue - you are correct also, but it is not iterating over it - but just calling the most recent one - one at a time(per back press or per onBackPressed()
call trigger), the documentation states:
public void onBackPressed()
Trigger a call to the currently added callbacks in reverse order in which they were added. Only if the most recently added callback is not
enabled
will any previously added callback be called.
If hasEnabledCallbacks is false when this method is called, the fallback Runnable set by
the constructor
will be triggered.
So your strategy here might be like this - if you need some specific stuff to be executed before the back navigation - you add it to the handleOnBackPressed
of the callback. If no special behavior needed - you can just call mOnBackPressedDispatcher.onBackPressed()
- it will still call the most recently added(if it is there of course) callback method, but if it is empty - the back will work just fine.
You need to keep in mind, though, that there are two overrides of addCallback
methods:
addCallback(@NonNull OnBackPressedCallback onBackPressedCallback)
and
public void addCallback(
@NonNull LifecycleOwner owner,
@NonNull OnBackPressedCallback onBackPressedCallback
)
In the former - you have to handle the callback queue by yourself calling remove
on callback when you need it not to be executed anymore. In the latter - LifecycleOwner
state change has to handle all the needed stuff for you.