问题描述
我有一个片段A,B,C。从A-> B导航时还可以,但从B-> C导航时它会崩溃。
这是我的导航
这是我的导航代码
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) }
}
}}