当我试图从一个片段导航到另一个片段时,我遇到了新的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。
任何帮助都将不胜感激。
当前回答
I am calling the 2.3.1 Navigation and the same error occurs when the application configuration changes. When the cause of the problem was found through Debug, the GaphId in NavHostFragment did not take effect as the ID currently set by calling navController.setGraph(). The GraphId of NavHostFragment can only be obtained from the <androidx.fragment.app.FragmentContainerView/> tag. At this time, this problem will occur if there are multiple GraphIds dynamically set in your code. When the interface is restored, the Destination cannot be found in the cached GraphId. You can solve this problem by manually specifying the value of mGraphId in NavHostFragment through reflection when switching Graph.
navController.setGraph(R.navigation.home_book_navigation);
try {
Field graphIdField = hostFragment.getClass().getDeclaredField("mGraphId");
graphIdField.setAccessible(true);
graphIdField.set(navHostFragment, R.navigation.home_book_navigation);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
其他回答
我在我的项目中也有同样的问题,首先我试图在视图上触发导航动作的点击,但经过一些实验后,我发现在真正缓慢的设备上,debounce应该是一个非常高的值,导致应用程序对快速设备的用户感到缓慢。
所以我为NavController提出了以下扩展,我认为它符合原始的API,并且易于使用:
fun NavController.safeNavigate(directions: NavDirections) {
try {
currentDestination?.getAction(directions.actionId) ?: return
navigate(directions.actionId, directions.arguments, null)
} catch (e : Exception) {
logError("Navigation error", e)
}
}
fun NavController.safeNavigate(directions: NavDirections, navOptions: NavOptions?) {
try {
currentDestination?.getAction(directions.actionId) ?: return
navigate(directions.actionId, directions.arguments, navOptions)
} catch (e : Exception) {
logError("Navigation error", e)
}
}
fun NavController.safeNavigate(directions: NavDirections, navigatorExtras: Navigator.Extras) {
try {
currentDestination?.getAction(directions.actionId) ?: return
navigate(directions.actionId, directions.arguments, null, navigatorExtras)
} catch (e : Exception) {
logError("Navigation error", e)
}
}
请注意,我正在使用SafeArgs和NavDirections。这些函数检查操作从当前目的地是否有效,并且仅在操作不为空时进行导航。如果Navigation库每次都返回正确的操作,那么try catch部分就不需要了,但我希望消除所有可能的崩溃。
您可以在导航之前检查请求导航的Fragment是否仍然是当前目的地,从这个要点出发。
它基本上是在片段上设置一个标记,以便稍后进行查找。
/**
* Returns true if the navigation controller is still pointing at 'this' fragment, or false if it already navigated away.
*/
fun Fragment.mayNavigate(): Boolean {
val navController = findNavController()
val destinationIdInNavController = navController.currentDestination?.id
val destinationIdOfThisFragment = view?.getTag(R.id.tag_navigation_destination_id) ?: destinationIdInNavController
// check that the navigation graph is still in 'this' fragment, if not then the app already navigated:
if (destinationIdInNavController == destinationIdOfThisFragment) {
view?.setTag(R.id.tag_navigation_destination_id, destinationIdOfThisFragment)
return true
} else {
Log.d("FragmentExtensions", "May not navigate: current destination is not the current fragment.")
return false
}
}
R.id。Tag_navigation_destination_id只是一个id,必须添加到ids.xml中,以确保它是唯一的。<item name="tag_navigation_destination_id" type="id" />
更多关于bug和解决方案的信息,以及navigateSafe(…)扩展方法在“修复可怕的”…是未知的NavController”
今天
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)
}
}
I am calling the 2.3.1 Navigation and the same error occurs when the application configuration changes. When the cause of the problem was found through Debug, the GaphId in NavHostFragment did not take effect as the ID currently set by calling navController.setGraph(). The GraphId of NavHostFragment can only be obtained from the <androidx.fragment.app.FragmentContainerView/> tag. At this time, this problem will occur if there are multiple GraphIds dynamically set in your code. When the interface is restored, the Destination cannot be found in the cached GraphId. You can solve this problem by manually specifying the value of mGraphId in NavHostFragment through reflection when switching Graph.
navController.setGraph(R.navigation.home_book_navigation);
try {
Field graphIdField = hostFragment.getClass().getDeclaredField("mGraphId");
graphIdField.setAccessible(true);
graphIdField.set(navHostFragment, R.navigation.home_book_navigation);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
将我的答案优雅地扔到处理两种情况(双击,同时点击两个按钮)的环中,但尽量不掩盖真正的错误。
我们可以使用navigateSafe()函数来检查我们试图导航到的目的地从当前目的地是否是无效的,但从前一个目的地是否是有效的。如果是这种情况,代码假设用户双击或同时点击两个按钮。
然而,这个解决方案并不完美,因为它可能会掩盖一些小众情况下的实际问题,即我们试图导航到恰好是父端的目的地。但据推测,这种情况不太可能发生。
代码:
fun NavController.navigateSafe(directions: NavDirections) {
val navigateWillError = currentDestination?.getAction(directions.actionId) == null
if (navigateWillError) {
if (previousBackStackEntry?.destination?.getAction(directions.actionId) != null) {
// This is probably some user tapping two different buttons or one button twice quickly
// Ignore...
return
}
// This seems like a programming error. Proceed and let navigate throw.
}
navigate(directions)
}