TL;DR 用try-catch 包裹您的navigate 呼叫(简单方法),或者确保在短时间内只有一个navigate 呼叫。这个问题很可能不会消失。在您的应用中复制更大的代码 sn-p 并试用。
你好。根据上面的几个有用的回答,我想分享我的可以扩展的解决方案。
这是导致我的应用程序崩溃的代码:
@Override
public void onListItemClicked(ListItem item) {
Bundle bundle = new Bundle();
bundle.putParcelable(SomeFragment.LIST_KEY, item);
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
}
轻松重现错误的一种方法是用多个手指点击项目列表,单击每个项目会在导航到新屏幕时解析(基本上与人们所说的相同 - 在很短的时间内点击两次或多次一段的时间)。我注意到:
- 第一次
navigate 调用总是可以正常工作;
-
navigate 方法的第二次和所有其他调用在 IllegalArgumentException 中解析。
在我看来,这种情况可能会经常出现。由于重复代码是一种不好的做法,而且有一点影响总是好的,我想到了下一个解决方案:
public class NavigationHandler {
public static void navigate(View view, @IdRes int destination) {
navigate(view, destination, /* args */null);
}
/**
* Performs a navigation to given destination using {@link androidx.navigation.NavController}
* found via {@param view}. Catches {@link IllegalArgumentException} that may occur due to
* multiple invocations of {@link androidx.navigation.NavController#navigate} in short period of time.
* The navigation must work as intended.
*
* @param view the view to search from
* @param destination destination id
* @param args arguments to pass to the destination
*/
public static void navigate(View view, @IdRes int destination, @Nullable Bundle args) {
try {
Navigation.findNavController(view).navigate(destination, args);
} catch (IllegalArgumentException e) {
Log.e(NavigationHandler.class.getSimpleName(), "Multiple navigation attempts handled.");
}
}
}
因此上面的代码只改变了一行:
Navigation.findNavController(recyclerView).navigate(R.id.action_listFragment_to_listItemInfoFragment, bundle);
到这里:
NavigationHandler.navigate(recyclerView, R.id.action_listFragment_to_listItemInfoFragment, bundle);
它甚至变得更短了。该代码在发生崩溃的确切位置进行了测试。没有再体验过,其他导航也会使用相同的解决方案,以进一步避免同样的错误。
欢迎提出任何想法!
究竟是什么导致了崩溃
请记住,当我们使用方法 Navigation.findNavController 时,我们使用相同的导航图、导航控制器和返回堆栈。
我们总是在这里得到相同的控制器和图形。当navigate(R.id.my_next_destination) 被调用时,返回堆栈几乎立即发生变化,而 UI 尚未更新。只是不够快,但没关系。后栈更改后,导航系统收到第二个navigate(R.id.my_next_destination) 调用。由于 back-stack 发生了变化,我们现在相对于堆栈中的顶部片段进行操作。顶部片段是您使用 R.id.my_next_destination 导航到的片段,但它不包含 ID 为 R.id.my_next_destination 的任何其他目的地。因此,您得到IllegalArgumentException,因为片段一无所知的ID。
这个确切的错误可以在NavController.java方法findDestination中找到。