导航组件Kotlin-从当前目的地找不到

问题描述

我有一个片段A,B,C。从A-> B导航时还可以,但从B-> C导航时它会崩溃。

这是我的导航

enter image description here

这是我的导航代码

 categoryProductItemlistadapter.setonItemClickListener {
        val action = CategoryProductItemsDirections.actionCategoryProductItems2ToProductItem(null,it)
        navController = Navigation.findNavController(requireView())
        navController?.navigateUp()
        navController?.navigate(action)
    }

这是productItem目的地的XML代码

<fragment
    android:id="@+id/categoryProductItems2"
    android:name="com.sample.store.main.dashboard.ui.ui.home.categoryitems.CategoryProductItems"
    android:label="CategoryProductItems"
    tools:layout="@layout/fragment_category_product_items">
    <argument
        android:name="category_global"
        app:argType="com.sample.store.data.globalmodels.response.categories.Category" />
    <action
        android:id="@+id/action_categoryProductItems2_to_productItem"
        app:destination="@id/productItem"
        app:enteranim="@anim/enter_from_right"
        app:exitAnim="@anim/exit_to_right"
        app:popEnteranim="@anim/fragment_open_enter"
        app:popExitAnim="@anim/fragment_fade_exit" />
</fragment>

这是错误

java.lang.IllegalArgumentException: Navigation action/destination com.sample.store.full:id/action_categoryProductItems2_to_productItem cannot be found from the current destination Destination(id/navigation_home) label=Home class=com.sample.store.main.dashboard.ui.ui.home.mainui.HomeFragment

我不知道发生了什么,但似乎navController正在寻找“ navigation_home”

解决方法

这与其说是一个答案,不如说是一个提示。但我希望它有所帮助。

总结:(正如其他人已经说过的:)连续调用导航函数是大多数这些异常的原因。

考虑到 android 组件的结构,特别是 MediatorLiveData 的工作方式,人们有时可能希望将数据节点加入单个可观察数据持有者 (LiveData)。

如果对这个中介的观察与动态导航功能相关联,那么无疑会出现错误。

原因是源可能会连续更改 LiveData 值,次数等于连接到 Mediator 的源数量。

这是一个非常好的主意,但是。重复更改 NavController 肯定会导致不良结果。

这可能包括:

  • 两次弹出 backStack。

  • 连续两次从 A -> B 出现 A 未找到的异常
    第二次。

这是一个很大的测试问题,特别是因为一个 Fragment 的问题可能会级联到底层堆栈,因此当一个 Fragment 中可能出现 Direction not found 异常时,真正的罪魁祸首可能是在 TOP 的 Fragment 上给出例外的那个。

实际上,这可以通过创建一个自取消线程执行器 scheduled.cancel(true); 来轻松解决,对 mediatorLiveData 本身具有延迟容忍度(准确地说是 onChange,而不是 setValue(),因为急切的内部状态更新是整个和调解人的唯一目的/笑话恕我直言(对不起,不允许 postValue()!))。

更不用说中介本身是一个不完整的组件...

另一种更简单的方法是确保当且仅当 !Object::Equals 时才执行来自 MutableLiveData 的 onChange 调用,并防止重复调用 onChange(),这仍然是 MediatorLiveData/LiveData 不完整的证明。 (使用列表时要格外小心)

不惜一切代价避免对 NavController 执行连续调用,如果您必须以某种方式执行,那么延迟运行可能是您实现它的唯一方法。

,

首先,在尝试检索Nav控制器-requireView()时,您不应传递navController = Navigation.findNavController(requireView())。您应该传递实际的Navigation Host Fragment实例。

第二个原因是由于您试图在片段A上从B-> C调用导航路径。

您的方向路径是从B-> C

val action = CategoryProductItemsDirections.actionCategoryProductItems2ToProductItem(null,it)

但是您首先要向上导航,因此实际上在尝试执行导航时您现在位于片段A上:

navController?.navigateUp()
navController?.navigate(action)
,

您需要设置defaultNavHost =“ true”。像本例一样:

if

也不要忘记在导航组件中设置家庭活动。

,

对于我来说,我通过替换-

解决了问题
 <action
    android:id="@+id/action_categoryProductItems2_to_productItem"
    app:destination="@id/productItem"
    app:enterAnim="@anim/enter_from_right"
    app:exitAnim="@anim/exit_to_right"
    app:popEnterAnim="@anim/fragment_open_enter"
    app:popExitAnim="@anim/fragment_fade_exit"/>

使用

 <action
    android:id="@+id/action_categoryProductItems2_to_productItem"
    app:destination="@id/productItem"
    app:enterAnim="@anim/enter_from_right"
    app:exitAnim="@anim/exit_to_right"
    app:popEnterAnim="@anim/fragment_open_enter"
    app:popExitAnim="@anim/fragment_fade_exit"
    app:popUpToInclusive="true" /* If true then also remove the destination from stack while popup */
    app:popUpTo="@id/navigation_home"/>  /*The fragment where to land again from destination*/
             
,

我创建了一个扩展函数来检查从当前目的地开始一个动作的可行性。

fun NavController.navigateSafe(@IdRes resId: Int,args: Bundle? = null) {
val destinationId = currentDestination?.getAction(resId)?.destinationId.orEmpty()
currentDestination?.let { node ->
    val currentNode = when (node) {
        is NavGraph -> node
        else -> node.parent
    }
    if (destinationId != EMPTY_INT) {
        currentNode?.findNode(destinationId)?.let { navigate(resId,args) }
    }
}}