Reputation: 990
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
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
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
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