当我试图从一个片段导航到另一个片段时,我遇到了新的Android导航架构组件的问题,我得到了这个奇怪的错误:

java.lang.IllegalArgumentException: navigation destination XXX
is unknown to this NavController

其他导航都很好,除了这个。

我使用Fragment的findNavController()函数来访问NavController。

任何帮助都将不胜感激。


当前回答

还有另一种解决快速点击导航崩溃问题的方法:

fun NavController.doIfCurrentDestination(@IdRes destination: Int, action: NavController.()-> Unit){
    if(this.currentDestination?.id == destination){action()}
}

然后像这样使用:

findNavController().doIfCurrentDestination(R.id.my_destination){ navigate(...) }

这种解决方案的好处是,您可以轻松地用您已经使用的任何签名包装任何现有的naagte()调用,而不需要进行一百万次重载

其他回答

我通过检查当前目标中是否存在下一个操作来解决这个问题

public static void launchFragment(BaseFragment fragment, int action) {
    if (fragment != null && NavHostFragment.findNavController(fragment).getCurrentDestination().getAction(action) != null) {       
        NavHostFragment.findNavController(fragment).navigate(action);
    }
}

public static void launchFragment(BaseFragment fragment, NavDirections directions) {
    if (fragment != null && NavHostFragment.findNavController(fragment).getCurrentDestination().getAction(directions.getActionId()) != null) {       
        NavHostFragment.findNavController(fragment).navigate(directions);
    }
}

这解决了一个问题,如果用户快速点击2个不同的按钮

在我的情况下,我有多个导航图文件,我试图从一个导航图位置移动到另一个导航图的目的地。

为此,我们必须将第二个导航图像这样包含在第一个导航图中

<include app:graph="@navigation/included_graph" />

并将此添加到你的行动中:

<action
        android:id="@+id/action_fragment_to_second_graph"
        app:destination="@id/second_graph" />

其中second_graph为:

<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">

在第二张图中。

更多信息请点击这里

将我的答案优雅地扔到处理两种情况(双击,同时点击两个按钮)的环中,但尽量不掩盖真正的错误。

我们可以使用navigateSafe()函数来检查我们试图导航到的目的地从当前目的地是否是无效的,但从前一个目的地是否是有效的。如果是这种情况,代码假设用户双击或同时点击两个按钮。

然而,这个解决方案并不完美,因为它可能会掩盖一些小众情况下的实际问题,即我们试图导航到恰好是父端的目的地。但据推测,这种情况不太可能发生。

代码:

fun NavController.navigateSafe(directions: NavDirections) {
    val navigateWillError = currentDestination?.getAction(directions.actionId) == null

    if (navigateWillError) {
        if (previousBackStackEntry?.destination?.getAction(directions.actionId) != null) {
            // This is probably some user tapping two different buttons or one button twice quickly
            // Ignore...
            return
        }

        // This seems like a programming error. Proceed and let navigate throw.
    }

    navigate(directions)
}

今天

def navigationVersion = "2.2.1"

这个问题仍然存在。我在Kotlin上的方法是:

// To avoid "java.lang.IllegalArgumentException: navigation destination is unknown to this NavController", se more https://stackoverflow.com/q/51060762/6352712
fun NavController.navigateSafe(
    @IdRes destinationId: Int,
    navDirection: NavDirections,
    callBeforeNavigate: () -> Unit
) {
    if (currentDestination?.id == destinationId) {
        callBeforeNavigate()
        navigate(navDirection)
    }
}

fun NavController.navigateSafe(@IdRes destinationId: Int, navDirection: NavDirections) {
    if (currentDestination?.id == destinationId) {
        navigate(navDirection)
    }
}

在思考了Ian Lake在推特上的建议后,我想出了以下方法。将NavControllerWrapper定义如下:

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

然后在导航代码中:

val navController = navControllerProvider.getNavController()
navController.navigate(from = R.id.main, to = R.id.action_to_detail)