当我试图从一个片段导航到另一个片段时,我遇到了新的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。
任何帮助都将不胜感激。
当前回答
在我的案例中,错误发生是因为我在启动画面后启用了带有Single Top和Clear Task选项的导航操作。
其他回答
似乎混合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导航。
在我的案例中,错误发生是因为我在启动画面后启用了带有Single Top和Clear Task选项的导航操作。
当我按了两次后退键时,我想到了这个问题。首先,我拦截KeyListener并覆盖KeyEvent.KEYCODE_BACK。我在名为OnResume的函数中添加了下面的代码,然后解决了这个问题/问题。
override fun onResume() {
super.onResume()
view?.isFocusableInTouchMode = true
view?.requestFocus()
view?.setOnKeyListener { v, keyCode, event ->
if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {
activity!!.finish()
true
}
false
}
}
当我第二次遇到这种情况时,它的状态与第一次相同,我发现我可能会使用add函数。让我们来分析一下这些情况。
首先,FragmentA导航到FragmentB,然后FragmentB导航到FragmentA,然后按下返回按钮…崩溃出现了。 其次,FragmentA导航到FragmentB,然后FragmentB导航到FragmentC, FragmentC导航到FragmentA,然后按下返回按钮…崩溃出现了。
所以我认为当按下返回按钮时,FragmentA会回到FragmentB或FragmentC,这会导致登录混乱。最后,我发现名为popBackStack的函数可以用于返回,而不是导航。
NavHostFragment.findNavController(this@TeacherCloudResourcesFragment).
.popBackStack(
R.id.teacher_prepare_lesson_main_fragment,false
)
到目前为止,问题已经真正解决了。
更新到@AlexNuts回答以支持导航到嵌套图。当一个动作使用一个嵌套图作为目的地时,如下所示:
<action
android:id="@+id/action_foo"
android:destination="@id/nested_graph"/>
此操作的目的ID不能与当前目的进行比较,因为当前目的不能是图形。必须解析嵌套图的起始目的地。
fun NavController.navigateSafe(directions: NavDirections) {
// Get action by ID. If action doesn't exist on current node, return.
val action = (currentDestination ?: graph).getAction(directions.actionId) ?: return
var destId = action.destinationId
val dest = graph.findNode(destId)
if (dest is NavGraph) {
// Action destination is a nested graph, which isn't a real destination.
// The real destination is the start destination of that graph so resolve it.
destId = dest.startDestination
}
if (currentDestination?.id != destId) {
navigate(directions)
}
}
然而,这将防止导航到同一目的地两次,这是有时需要的。为了允许这一点,你可以添加一个检查action.navOptions?. shouldlaunchsingletop(),并添加app:launchSingleTop="true"的动作,你不希望重复的目的地。
在我的情况下,问题发生时,我重用了我的片段内的一个viewpager片段作为viewpager的子。 viewpager片段(父片段)被添加到Navigation xml中,但动作没有添加到viewpager父片段中。
nav.xml
//reused fragment
<fragment
android:id="@+id/navigation_to"
android:name="com.package.to_Fragment"
android:label="To Frag"
tools:layout="@layout/fragment_to" >
//issue got fixed when i added this action to the viewpager parent also
<action android:id="@+id/action_to_to_viewall"
app:destination="@+id/toViewAll"/>
</fragment>
....
// viewpager parent fragment
<fragment
android:id="@+id/toViewAll"
android:name="com.package.ViewAllFragment"
android:label="to_viewall_fragment"
tools:layout="@layout/fragment_view_all">
修正了添加动作到父viewpager片段的问题,如下所示:
nav.xml
//reused fragment
<fragment
android:id="@+id/navigation_to"
android:name="com.package.to_Fragment"
android:label="To Frag"
tools:layout="@layout/fragment_to" >
//issue got fixed when i added this action to the viewpager parent also
<action android:id="@+id/action_to_to_viewall"
app:destination="@+id/toViewAll"/>
</fragment>
....
// viewpager parent fragment
<fragment
android:id="@+id/toViewAll"
android:name="com.package.ViewAllFragment"
android:label="to_viewall_fragment"
tools:layout="@layout/fragment_view_all"/>
<action android:id="@+id/action_to_to_viewall"
app:destination="@+id/toViewAll"/>
</fragment>