当我试图从一个片段导航到另一个片段时,我遇到了新的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。
任何帮助都将不胜感激。
当前回答
如果你使用的是recyclerview,只需在你的点击上添加一个点击监听器冷却时间,并在你的recyclerview xml文件中使用android:splitMotionEvents="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"的动作,你不希望重复的目的地。
为了防止崩溃,我采取了如下措施:
我有一个BaseFragment,在那里我添加了这个乐趣,以确保目的地是已知的currentDestination:
fun navigate(destination: NavDirections) = with(findNavController()) {
currentDestination?.getAction(destination.actionId)
?.let { navigate(destination) }
}
值得注意的是,我正在使用SafeArgs插件。
在我的情况下,我通过验证所有导航操作都正确地管理到各自的图形中,并更新了设备后退按钮的代码来解决这个问题,如下所示:
onBackPressedDispatcher.addCallback(this /* lifecycle owner */, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Back is pressed... Finishing the activity
if (navHostFragment.childFragmentManager.backStackEntryCount == 0) {
// First fragment is open, backstack is empty
finish()
} else {
navHostFragment.navController.popBackStack()
}
}
})
I caught this exception after some renames of classes. For example: I had classes called FragmentA with @+is/fragment_a in navigation graph and FragmentB with @+id/fragment_b. Then I deleted FragmentA and renamed FragmentB to FragmentA. So after that node of FragmentA still stayed in navigation graph, and android:name of FragmentB's node was renamed path.to.FragmentA. I had two nodes with the same android:name and different android:id, and the action I needed were defined on node of removed class.
在思考了Ian Lake在推特上的建议后,我想出了以下方法。将NavControllerWrapper定义如下:
class NavControllerWrapper constructor(
private val navController: NavController
) {
fun navigate(
@IdRes from: Int,
@IdRes to: Int
) = navigate(
from = from,
to = to,
bundle = null
)
fun navigate(
@IdRes from: Int,
@IdRes to: Int,
bundle: Bundle?
) = navigate(
from = from,
to = to,
bundle = bundle,
navOptions = null,
navigatorExtras = null
)
fun navigate(
@IdRes from: Int,
@IdRes to: Int,
bundle: Bundle?,
navOptions: NavOptions?,
navigatorExtras: Navigator.Extras?
) {
if (navController.currentDestination?.id == from) {
navController.navigate(
to,
bundle,
navOptions,
navigatorExtras
)
}
}
fun navigate(
@IdRes from: Int,
directions: NavDirections
) {
if (navController.currentDestination?.id == from) {
navController.navigate(directions)
}
}
fun navigateUp() = navController.navigateUp()
fun popBackStack() = navController.popBackStack()
}
然后在导航代码中:
val navController = navControllerProvider.getNavController()
navController.navigate(from = R.id.main, to = R.id.action_to_detail)