I am having issue with the new Android Navigation Architecture component when I try to navigate from one Fragment to another, I get this weird error:
In my case, I had multiple nav graph files and I was trying to move from 1 nav graph location to a destination in another nav graph.
For this we have to include the 2nd nav graph in the 1st one like this
<include app:graph="@navigation/included_graph" />
and add this to your action:
<action
android:id="@+id/action_fragment_to_second_graph"
app:destination="@id/second_graph" />
where second_graph
is :
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/second_graph"
app:startDestination="@id/includedStart">
in the second graph.
More info here
In order to avoid this crash one of my colleagues wrote a small library which exposes a SafeNavController
, a wrapper around the NavController
and handles the cases when this crash occurs because of multiple navigate commands at the same time.
Here is a short article about the whole issue and the solution.
You can find the library here.
This happened to me, my issue was I was clicking a FAB on tab item fragment
. I was trying to navigate from one of tab item fragment to another fragment
.
But according to Ian Lake in this answer we have to use tablayout
and viewpager
, no navigation component support. Because of this, there is no navigation path from tablayout containing fragment to tab item fragment.
ex:
containing fragment -> tab layout fragment -> tab item fragment -> another fragment
Solution was to create a path from tab layout containing fragment to intended fragment
ex: path: container fragment -> another fragment
Disadvantage:
In my case the bug ocurred because I had a navigation action with the Single Top
and the Clear Task
options enabled after a splash screen.
It seems that mixing fragmentManager control of the backstack and Navigation Architecture control of the backstack can cause this issue also.
For example the original CameraX basic sample used fragmentManager backstack navigation as below and it appears as if it did not correctly interact with Navigation:
// Handle back button press
view.findViewById<ImageButton>(R.id.back_button).setOnClickListener {
fragmentManager?.popBackStack()
}
If you log the 'current destination' with this version before moving from the main fragment (the camera fragment in this case) and then log it again when you return to the main fragment, you can see from the id in the logs that the id is not the same. At a guess, the Navigation updated it when moving to the fragment and the fragmntManager did not then update it again when moving back. From the logs:
Before: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator$Destination@b713195
After: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator$Destination@9807d8f
The updated version of CameraX basic sample uses Navigation to return like this:
// Handle back button press
view.findViewById<ImageButton>(R.id.back_button).setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigateUp()
}
This works correctly and the logs show the same id when back at the main fragment.
Before: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator$Destination@b713195
After: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator$Destination@b713195
I suspect the moral of the story, at least at this time, is to be very careful mixing Navigation with fragmentManager navigation.
I wrote this extensions
fun Fragment.navigateAction(action: NavDirections) {
val navController = this.findNavController()
if (navController.currentDestination?.getAction(action.actionId) == null) {
return
} else {
navController.navigate(action)
}
}