Fixing the dreaded “… is unknown to this NavController”

Frank
2 min readMay 4, 2020

--

Did you encounter the “IllegalArgumentException: X is unknown to this NavController” in your crash logs while you feel that your navigation setup is valid? You’re not the only one. Let’s fix it!

The cause

You would experience the exception when you are trying to navigate to a destination that is not included in the current navigation graph. This could be an implementation mistake on your part, but if you’re sure it’s not: in the world of Fragments this also happens when you trigger a (second) navigation request from a fragment that is no longer the current location (currentDestination) in the navController. In other words, when navigating from A to B, there is a moment when:

  • Fragment A is still active and showing.
  • The navigation library already changed its current location,currentDestination, to Fragment B.

When a second request to navigate from fragment A comes in at exactly this moment, and it uses a destination that is not included in B’s graph: 💥kaboom.

Reproducing

You can reproduce this by wildly clicking your buttons at the same time or by mimicking it in your code. When B is not a valid destination in its own navigation graph (B cannot navigate to B), this code in Fragment A will crash your app:

navController.navigate(actionToB) // 👍 currentDestination A -> B
navController.navigate(actionToB) // 💥 there is no actionToB in B

The navigation library developers are not going to fix this problem, as written in this bug report, because they feel it’s the Fragment’s responsibility.

Fixing

Jake Lee wrote a good solution to resolve this error. Here’s an extension method that makes his solution more generic: Fragment.mayNavigate()

mayNavigate will return true if the current Fragment is still the current one according to the NavController. If it’s not, then we should not do the navigate call, because we’re already navigating away from the current Fragment.

The inners

Inside mayNavigate, the function adds the current destination as one of the fragment’s view tags, so that on the next navigate call we can check if the fragment doing the navigate call is also still the ‘current fragment’ according to the navigation library.

More goodies: navigateSafe()

To ease its use, I added more extension methods, so we can simply replace all findNavController().navigate() calls with the safer navigateSafe(…) in our Fragments’ code as shown in this gist.

Bye-bye crash, hello sleep! Let me know if you see any room for improvement.

--

--