当我试图从一个片段导航到另一个片段时,我遇到了新的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()调用,而不需要进行一百万次重载

其他回答

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.

当我按了两次后退键时,我想到了这个问题。首先,我拦截KeyListener并覆盖KeyEvent.KEYCODE_BACK。我在名为OnResume的函数中添加了下面的代码,然后解决了这个问题/问题。

  override fun onResume() {
        super.onResume()
        view?.isFocusableInTouchMode = true
        view?.requestFocus()
        view?.setOnKeyListener { v, keyCode, event ->
            if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
                activity!!.finish()
                true
            }
            false
        }
    }

当我第二次遇到这种情况时,它的状态与第一次相同,我发现我可能会使用add函数。让我们来分析一下这些情况。

首先,FragmentA导航到FragmentB,然后FragmentB导航到FragmentA,然后按下返回按钮…崩溃出现了。 其次,FragmentA导航到FragmentB,然后FragmentB导航到FragmentC, FragmentC导航到FragmentA,然后按下返回按钮…崩溃出现了。

所以我认为当按下返回按钮时,FragmentA会回到FragmentB或FragmentC,这会导致登录混乱。最后,我发现名为popBackStack的函数可以用于返回,而不是导航。

  NavHostFragment.findNavController(this@TeacherCloudResourcesFragment).
                        .popBackStack(
                            R.id.teacher_prepare_lesson_main_fragment,false
                        )

到目前为止,问题已经真正解决了。

在我的例子中,我使用了一个自定义的后退按钮来向上导航。我调用了onBackPressed()而不是下面的代码

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

这导致发生IllegalArgumentException。在我将其更改为使用navigateUp()方法之后,我就不会再次崩溃了。

为了防止崩溃,我采取了如下措施:

我有一个BaseFragment,在那里我添加了这个乐趣,以确保目的地是已知的currentDestination:

fun navigate(destination: NavDirections) = with(findNavController()) {
    currentDestination?.getAction(destination.actionId)
        ?.let { navigate(destination) }
}

值得注意的是,我正在使用SafeArgs插件。

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

我们可以使用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)
}