Cyd*_*Cyd 21 android kotlin android-architecture-navigation
我有一个片段 A、B、C。从 A -> B 导航时没问题,但从 B -> C 时它崩溃了。
这是我的导航
这是我的导航代码
categoryProductItemListAdapter.setOnItemClickListener {
val action = CategoryProductItemsDirections.actionCategoryProductItems2ToProductItem(null, it)
navController = Navigation.findNavController(requireView())
navController?.navigateUp()
navController?.navigate(action)
}
Run Code Online (Sandbox Code Playgroud)
这是 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>
Run Code Online (Sandbox Code Playgroud)
这是错误:
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
Run Code Online (Sandbox Code Playgroud)
我不知道发生了什么,但似乎 navController 正在寻找“navigation_home”
vis*_*nny 17
我创建了一个扩展函数来检查从当前目的地开始操作的可行性。
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 != 0) {
currentNode?.findNode(destinationId)?.let { navigate(resId, args) }
}
}}
Run Code Online (Sandbox Code Playgroud)
该orEmpty()部分扩展Int?如下:
fun Int?.orEmpty(default: Int = 0): Int {
return this ?: default
}
Run Code Online (Sandbox Code Playgroud)
Del*_*ark 17
这与其说是一个答案,不如说是一个提醒。但我希望它有所帮助。
总结:(正如其他人已经说过的:)对 Navigation 函数的连续调用是大多数这些异常的原因。
考虑到 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 执行连续调用,如果您必须以某种方式执行,那么延迟运行可能是您实现它的唯一方法。
首先,requireView()在尝试检索您的导航控制器时不应该通过- navController = Navigation.findNavController(requireView())。您应该传递实际的导航主机片段实例。
其次,问题是因为您试图在片段 A 上从 B -> C 调用导航路径。
您的方向路径是从 B -> C
val action = CategoryProductItemsDirections.actionCategoryProductItems2ToProductItem(null, it)
Run Code Online (Sandbox Code Playgroud)
但是您首先向上导航,因此在尝试执行导航时您实际上现在位于片段 A 上:
navController?.navigateUp()
navController?.navigate(action)
Run Code Online (Sandbox Code Playgroud)
小智 7
//通过传递id检查当前fragment是否是事件触发fragment
fun Fragment.findNavControllerSafely(id: Int): NavController? {
return if (findNavController().currentDestination?.id == id) {
findNavController()
} else {
null
}
}
Run Code Online (Sandbox Code Playgroud)
//在调用导航的片段中实现
findNavControllerSafely(R.id.fragment1)?.navigate(
R.id.action_fragment1_to_fragment2, bundle
)
Run Code Online (Sandbox Code Playgroud)
下面是用于安全导航的 Java 版本的 NavigationUtils 类:
public abstract class NavigationUtils {
/**
* This function will check navigation safety before starting navigation using direction
*
* @param navController NavController instance
* @param direction navigation operation
*/
public static void navigateSafe(NavController navController, NavDirections direction) {
NavDestination currentDestination = navController.getCurrentDestination();
if (currentDestination != null) {
NavAction navAction = currentDestination.getAction(direction.getActionId());
if (navAction != null) {
int destinationId = orEmpty(navAction.getDestinationId());
NavGraph currentNode;
if (currentDestination instanceof NavGraph)
currentNode = (NavGraph) currentDestination;
else
currentNode = currentDestination.getParent();
if (destinationId != 0 && currentNode != null && currentNode.findNode(destinationId) != null) {
navController.navigate(direction);
}
}
}
}
/**
* This function will check navigation safety before starting navigation using resId and args bundle
*
* @param navController NavController instance
* @param resId destination resource id
* @param args bundle args
*/
public static void navigateSafe(NavController navController, @IdRes int resId, Bundle args) {
NavDestination currentDestination = navController.getCurrentDestination();
if (currentDestination != null) {
NavAction navAction = currentDestination.getAction(resId);
if (navAction != null) {
int destinationId = orEmpty(navAction.getDestinationId());
NavGraph currentNode;
if (currentDestination instanceof NavGraph)
currentNode = (NavGraph) currentDestination;
else
currentNode = currentDestination.getParent();
if (destinationId != 0 && currentNode != null && currentNode.findNode(destinationId) != null) {
navController.navigate(resId, args);
}
}
}
}
private static int orEmpty(Integer value) {
return value == null ? 0 : value;
}
}
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用这个类:
NavController navController = Navigation.findNavController(view);
NavigationUtils.navigateSafe(navController, R.id.action_firstFragment_to_secondFragment, null);
Run Code Online (Sandbox Code Playgroud)
或者:
NavController navController = Navigation.findNavController(view);
NavDirections direction = FirstFragmentDirections.actionFirstFragmentToSecondFragment(yourModel, bundleArgs);
NavigationUtils.navigateSafe(navController, direction);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
19736 次 |
| 最近记录: |