javaandroidkotlinandroid-fragmentsonbackpressed

Handling back press from fragment after app get's back from background


I want to handle user back presses in one of the activity's (Java) fragments (Kotlin).

In activity's onCreate method I call

OnBackPressedCallback onBackPressedCallback = new OnBackPressedCallback(true) { 
(...) handling back press when there's other BackPressedDispatcherCallbacks registered (...)
}
getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);

Then in onCreateView() of a fragment that I want to handle back press instead, I call

activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
(...) handling back press here, not in activity (...)
}})

Everything works as expected until I get the app in the background and then back into the foreground, causing OnStop -> OnStart of both Activity and Fragment to be called.

When this is the case application ignores Fragment callback and Activity's callback is being invoked.

What I figured out is that

  1. onBackPressedDispatcher calls 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 (only last enabled callback is being invoked)

  2. Adding an observer to both Activity and Fragment lifecycles and logging result prints:

    FRAG: ON_START ACT: ON_START FRAG: ON_RESUME ACT: ON_RESUME

Activity on OnStart and OnResume gets called after Fragments equivalents, which effectively makes Activity's callback being last active one and receiving back event instead of the fragment.

I'm looking for a solution to that. I would really appreciate any suggestions on how to push it forward.

PS. Approach with calling last fragments method (last on the stack of activity fragmentManager) is not going to work, as currently, it's crucial for the app that these fragments are NOT added to back stack.


Solution

  • You can just use in the activity

    getOnBackPressedDispatcher().addCallback(onBackPressedCallback);
    

    Instead of

    getOnBackPressedDispatcher().addCallback(this, onBackPressedCallback);
    

    If you don't pass the lyfecycleOwner in addCallback the callback is immediatly added to the chain of responsibility, so you don't have to wait for the activity state to be STARTED