使用 androidx.navigation 时随机崩溃

Random crashes when using androidx.navigation

使用时

'androidx.navigation:navigation-ui-ktx:2.3.0' 
'androidx.navigation:navigation-fragment-ktx:2.3.0' 

该应用程序正常运行了一段时间,直到我开始随机获取

 Navigation action/destination cannot be found from the current destination NavGraph

当我点击任何触发导航的按钮时,我使用这样的导航

//to navigate 
var dir = MainMenuDirections.actionMainMenuToSelectPayments()
NavHostFragment.findNavController(this).navigate(dir)

//to pop current fragment
NavHostFragment.findNavController(this).popBackStack()

我试过使用 2.2.0 版

显然这是自版本 1.0.0 alpha 4 以来存在的错误,当您在调用 popBackStack() 之后调用 Navigate() 时会发生这种情况,很奇怪每个人是如何使用它的?

如果有人犯了我犯的错误,我会从问题跟踪器得到答案

这与 b/128734685 类似,其中 nav.popBackStack() 返回 false 意味着仍然从后台堆栈中删除您的 login2。

这就是错误消息显示的原因:

java.lang.IllegalArgumentException: Navigation action/destination com.dzdoes.i.payments:id/action_login2_to_registre cannot be found from the current destination NavGraph(com.dzdoes.i.payments:id/nav_graph) startDestination={Destination(com.dzdoes.i.payments:id/login2) label=Login class=com.dzdoes.i.payments.ui.Auth.Login}
Correctly indicating that you are not on the login2 destination (you are on the root nav_graph, which correctly does not have an action named action_login2_to_registre).

这是预期的行为,正如在另一个问题中提到的,您仍然在屏幕上看到片段的唯一原因是允许 activity 动画完成且片段仍然可见(而不是动画一个空 activity).

你有两个选择:

停止覆盖 onBackPressed()。相反,您应该遵循提供的自定义后退导航,并在 activity 级别注册您自己的 OnBackPressedCallback 回调,没有 LifecycleOwner。这将确保它仅在没有导航返回堆栈时触发:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...

    onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            val builder: AlertDialog.Builder = AlertDialog.Builder(this@NavHostAuth)
            builder
                .setMessage("are you sure you want to exit")
                .setPositiveButton("yes") { _, _ -> finish() }
                .setNegativeButton("no") { _, _ -> }
                .show()
        }
    })
}

请注意,您需要将 app:defaultNavHost="true" 添加到 XML,因为这是导致 NavHostFragment 默认正确拦截后退按钮的原因。这是实现此功能的推荐方法。

更新您的 setNegativeButton 以再次导航到您的起始目的地。

.setNegativeButton(
    "no",
    DialogInterface.OnClickListener { dialog, which -> nav.navigate(R.id.login2) })

请注意,在任何一种情况下,您都不需要从 setNegativeButton 侦听器调用 dialog.dismiss() - 只要按下肯定或否定按钮,AlertDialog 就会自动消失.