当我试图从一个片段导航到另一个片段时,我遇到了新的Android导航架构组件的问题,我得到了这个奇怪的错误:
java.lang.IllegalArgumentException: navigation destination XXX
is unknown to this NavController
其他导航都很好,除了这个。
我使用Fragment的findNavController()函数来访问NavController。
任何帮助都将不胜感激。
当我试图从一个片段导航到另一个片段时,我遇到了新的Android导航架构组件的问题,我得到了这个奇怪的错误:
java.lang.IllegalArgumentException: navigation destination XXX
is unknown to this NavController
其他导航都很好,除了这个。
我使用Fragment的findNavController()函数来访问NavController。
任何帮助都将不胜感激。
当前回答
似乎混合fragmentManager控件的backstack和Navigation Architecture控件的backstack也会导致这个问题。
例如,最初的CameraX基本示例使用fragmentManager后台导航,如下所示,它似乎没有正确地与导航交互:
// Handle back button press
view.findViewById<ImageButton>(R.id.back_button).setOnClickListener {
fragmentManager?.popBackStack()
}
如果你在从主片段(在本例中是相机片段)移动之前记录这个版本的“当前目的地”,然后当你返回主片段时再次记录它,你可以从日志中的id中看到id是不相同的。据猜测,导航在移动到片段时更新了它,而fragmntManager在移动回来时没有再次更新它。日志显示:
修改前:D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@b713195美元 After: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@9807d8f美元
更新版的CameraX基本示例使用导航返回如下:
// Handle back button press
view.findViewById<ImageButton>(R.id.back_button).setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigateUp()
}
这可以正常工作,当返回到主片段时,日志显示相同的id。
修改前:D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@b713195美元 After: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@b713195美元
我怀疑这个故事的寓意,至少在这个时候,是要非常小心地混合导航和fragmentManager导航。
其他回答
如果你有的话,这种情况也会发生 一个片段a和片段B的ViewPager 你试着从B导航到C
因为在ViewPager中片段不是a的目的地,所以你的图形不会知道你在B上。
一种解决方案是在B中使用A方向导航到C
似乎混合fragmentManager控件的backstack和Navigation Architecture控件的backstack也会导致这个问题。
例如,最初的CameraX基本示例使用fragmentManager后台导航,如下所示,它似乎没有正确地与导航交互:
// Handle back button press
view.findViewById<ImageButton>(R.id.back_button).setOnClickListener {
fragmentManager?.popBackStack()
}
如果你在从主片段(在本例中是相机片段)移动之前记录这个版本的“当前目的地”,然后当你返回主片段时再次记录它,你可以从日志中的id中看到id是不相同的。据猜测,导航在移动到片段时更新了它,而fragmntManager在移动回来时没有再次更新它。日志显示:
修改前:D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@b713195美元 After: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@9807d8f美元
更新版的CameraX基本示例使用导航返回如下:
// Handle back button press
view.findViewById<ImageButton>(R.id.back_button).setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigateUp()
}
这可以正常工作,当返回到主片段时,日志显示相同的id。
修改前:D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@b713195美元 After: D/CameraXBasic: currentDest?: androidx.navigation.fragment.FragmentNavigator Destination@b713195美元
我怀疑这个故事的寓意,至少在这个时候,是要非常小心地混合导航和fragmentManager导航。
今天
def navigationVersion = "2.2.1"
这个问题仍然存在。我在Kotlin上的方法是:
// To avoid "java.lang.IllegalArgumentException: navigation destination is unknown to this NavController", se more https://stackoverflow.com/q/51060762/6352712
fun NavController.navigateSafe(
@IdRes destinationId: Int,
navDirection: NavDirections,
callBeforeNavigate: () -> Unit
) {
if (currentDestination?.id == destinationId) {
callBeforeNavigate()
navigate(navDirection)
}
}
fun NavController.navigateSafe(@IdRes destinationId: Int, navDirection: NavDirections) {
if (currentDestination?.id == destinationId) {
navigate(navDirection)
}
}
在调用navigate之前检查currentDestination可能会有帮助。
例如,如果您在导航图fragmentA和fragmentB上有两个片段目的地,并且从fragmentA到fragmentB只有一个动作。当你已经在fragmentB上时,调用navigate(R.id.action_fragmentA_to_fragmentB)将导致IllegalArgumentException。因此,在导航之前,你应该总是检查currentDestination。
if (navController.currentDestination?.id == R.id.fragmentA) {
navController.navigate(R.id.action_fragmentA_to_fragmentB)
}
我为Fragment创建了这个扩展函数:
fun Fragment.safeNavigate(
@IdRes actionId: Int,
@Nullable args: Bundle? = null,
@Nullable navOptions: NavOptions? = null,
@Nullable navigatorExtras: Navigator.Extras? = null
) {
NavHostFragment.findNavController(this).apply {
if (currentDestination?.label == this@safeNavigate::class.java.simpleName) {
navigate(actionId, args, navOptions, navigatorExtras)
}
}
}