Jason Toms
Jason Toms

Reputation: 990

OnBackPressedCallback is being called, but app is not going back

I recently updated my dependencies to include the OnBackPressedCallback change from an interface into an abstract class.

I have set things up according to the new documentation here but I feel like things are not working as they should.

My fragment's OnCreate looks a lot like the documentation:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        requireActivity().onBackPressedDispatcher.addCallback(this) {
            backPressed()
    }
}

When I press the back button, the code in backPressed() is run, but nothing more happens.

I have tried calling handleBackPressed() and requireActivity().onBackPressedDispatcher.onBackPressed() and requireActivity().onBackPressed() from inside the callback, but those all cause a StackOverflowError because it seems to run that callback recursively.

There has got to be something really obvious I am missing...

Upvotes: 15

Views: 28221

Answers (4)

Thracian
Thracian

Reputation: 67149

You can also remove callback instead of setting enabled if it's no longer needed. I use it with nested graph like this because when you touch back in a nested nav graph with it's NavHostFragment, it removes it from main fragment back stack instead of opening last fragment in nested nav graph.

   // Get NavHostFragment
    val navHostFragment =
        childFragmentManager.findFragmentById(R.id.nested_nav_host_fragment)

    // ChildFragmentManager of the current NavHostFragment
    val navHostChildFragmentManager = navHostFragment?.childFragmentManager

       val callback = object : OnBackPressedCallback(true) {

        override fun handleOnBackPressed() {

            val backStackEntryCount = navHostChildFragmentManager!!.backStackEntryCount


            if (backStackEntryCount == 1) {
                // We are at the root of nested navigation, remove this callback
                remove()
                requireActivity().onBackPressed()
            } else {
                navController?.navigateUp()
            }
        }
    }

    requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)

Upvotes: 5

Анатолий К.
Анатолий К.

Reputation: 281

There has got to be something really obvious I am missing...

You forget to disable your custom callback in you fragment before asking Activity to handle back pressed.

My solutiuon suitable for me:

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

        final OnBackPressedCallback callback = new OnBackPressedCallback(true) {
            @Override
            public void handleOnBackPressed() {
               if (/*situation to handle back pressing*/){
                //here handle your backPress in your fragment
                } else {
                   setEnabled(false); //this is important line
                   requireActivity().onBackPressed();
                }
            }
        };
        requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
    }

Upvotes: 26

aaronmarino
aaronmarino

Reputation: 4002

This works for me in androidx.appcompat:appcompat:1.1.0

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()
                }
            }
        }
    )

Upvotes: 10

ianhanniballake
ianhanniballake

Reputation: 200010

When you register an OnBackPressedCallback, you are taking on the responsibility for handling the back button. That means that no other on back pressed behavior is going to occur when you get a callback.

If you're using Navigation, you can use your NavController to pop the back stack:

requireActivity().onBackPressedDispatcher.addCallback(this) {
    backPressed()
    // Now actually go back
    findNavController().popBackStack()
}

Upvotes: 11

Related Questions