IllegalArgumentException: navigation destination xxx is unknown to this NavController

后端 未结 30 2105
遇见更好的自我
遇见更好的自我 2020-11-27 11:28

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:

相关标签:
30条回答
  • 2020-11-27 12:17

    I got this same error because I used a Navigation Drawer and getSupportFragmentManager().beginTransaction().replace( ) at the same time somewhere in my code .

    I got rid of the error by using this condition(testing if the destination) :

    if (Navigation.findNavController(v).getCurrentDestination().getId() == R.id.your_destination_fragment_id)
    Navigation.findNavController(v).navigate(R.id.your_action);
    

    In my case the previous error was triggered when I was clicking on the navigation drawer options. Basically the code above did hide the error , because in my code somewhere I used navigation using getSupportFragmentManager().beginTransaction().replace( ) The condition -

     if (Navigation.findNavController(v).getCurrentDestination().getId() ==
      R.id.your_destination_fragment_id) 
    

    was never reached because (Navigation.findNavController(v).getCurrentDestination().getId() was always poiting to home fragment. You must only use Navigation.findNavController(v).navigate(R.id.your_action) or nav graph controller functions for all your navigation actions.

    0 讨论(0)
  • 2020-11-27 12:17

    I caught this exception after some renames of classes. For example: I had classes called FragmentA with @+is/fragment_a in navigation graph and FragmentB with @+id/fragment_b. Then I deleted FragmentA and renamed FragmentB to FragmentA. So after that node of FragmentA still stayed in navigation graph, and android:name of FragmentB's node was renamed path.to.FragmentA. I had two nodes with the same android:name and different android:id, and the action I needed were defined on node of removed class.

    0 讨论(0)
  • 2020-11-27 12:22

    A Ridiculous way but very powerful is: Simply call this:

    view?.findNavController()?.navigateSafe(action)
    

    Just Create this Extention:

    fun NavController.navigateSafe(
        navDirections: NavDirections? = null
    ) {
        try {
            navDirections?.let {
                this.navigate(navDirections)
            }
        }
        catch (e:Exception)
        {
            e.printStackTrace()
        }
    }
    
    0 讨论(0)
  • 2020-11-27 12:23

    In my case I was using a custom back button for navigating up. I called onBackPressed() in stead of the following code

    findNavController(R.id.navigation_host_fragment).navigateUp()
    

    This caused the IllegalArgumentException to occur. After I changed it to use the navigateUp() method in stead, I didn't have a crash again.

    0 讨论(0)
  • 2020-11-27 12:23

    You can check before navigating if the Fragment requesting the navigation is still the current destination, taken from this gist.

    It basically sets a tag on the fragment for later lookup.

    /**
     * Returns true if the navigation controller is still pointing at 'this' fragment, or false if it already navigated away.
     */
    fun Fragment.mayNavigate(): Boolean {
    
        val navController = findNavController()
        val destinationIdInNavController = navController.currentDestination?.id
        val destinationIdOfThisFragment = view?.getTag(R.id.tag_navigation_destination_id) ?: destinationIdInNavController
    
        // check that the navigation graph is still in 'this' fragment, if not then the app already navigated:
        if (destinationIdInNavController == destinationIdOfThisFragment) {
            view?.setTag(R.id.tag_navigation_destination_id, destinationIdOfThisFragment)
            return true
        } else {
            Log.d("FragmentExtensions", "May not navigate: current destination is not the current fragment.")
            return false
        }
    }
    

    R.id.tag_navigation_destination_id is just an id you'll have to add to your ids.xml, to make sure it's unique. <item name="tag_navigation_destination_id" type="id" />

    More info on the bug and the solution, and navigateSafe(...) extention methods in "Fixing the dreaded “… is unknown to this NavController”

    0 讨论(0)
  • 2020-11-27 12:24

    After thinking over Ian Lake's advice in this twitter thread I've came up with following approach. Having NavControllerWrapper defined as such:

    class NavControllerWrapper constructor(
      private val navController: NavController
    ) {
    
      fun navigate(
        @IdRes from: Int,
        @IdRes to: Int
      ) = navigate(
        from = from,
        to = to,
        bundle = null
      )
    
      fun navigate(
        @IdRes from: Int,
        @IdRes to: Int,
        bundle: Bundle?
      ) = navigate(
        from = from,
        to = to,
        bundle = bundle,
        navOptions = null,
        navigatorExtras = null
      )
    
      fun navigate(
        @IdRes from: Int,
        @IdRes to: Int,
        bundle: Bundle?,
        navOptions: NavOptions?,
        navigatorExtras: Navigator.Extras?
      ) {
        if (navController.currentDestination?.id == from) {
          navController.navigate(
            to,
            bundle,
            navOptions,
            navigatorExtras
          )
        }
      }
    
      fun navigate(
        @IdRes from: Int,
        directions: NavDirections
      ) {
        if (navController.currentDestination?.id == from) {
          navController.navigate(directions)
        }
      }
    
      fun navigateUp() = navController.navigateUp()
    
      fun popBackStack() = navController.popBackStack()
    }
    
    

    Then in navigation code:

    val navController = navControllerProvider.getNavController()
    navController.navigate(from = R.id.main, to = R.id.action_to_detail)
    
    
    0 讨论(0)
提交回复
热议问题