Jetpack Compose嵌套导航图内的路由是否必须全局唯一?
Jetpack Compose嵌套导航图重复子路由崩溃问题分析
问题重现
在嵌套导航图中定义了两个内部路由相同的子图:
navigation(route = "a", startDestination = "b") { composable("b") { Button(onClick = { navController.navigate("c") }) { Text("ab") } } composable("c") { Button(onClick = { navController.navigate("b") }) { Text("ac") } } } navigation(route = "x", startDestination = "b") { composable("b") { Button(onClick = { navController.navigate("c") }) { Text("xb") } } composable("c") { Button(onClick = { navController.navigate("b") }) { Text("xc") } } }
第一个子图(home -> "a" -> "b" -> "c")导航正常,但第二个子图(home -> "x" -> "b")点击按钮跳转至"c"时抛出异常:
E/AndroidRuntime: FATAL EXCEPTION: main Process: eu.dateio.dateiosdkmutliplatform.android.demo, PID: 5052 java.lang.IllegalArgumentException: No destination with ID -443542924 is on the NavController's back stack. The current destination is Destination(0xe5901276) route=c ...
原因分析
这不是导航库的Bug,而是NavController的路由ID生成机制导致的:
- NavController会根据路由字符串生成唯一的Destination ID,相同的路由字符串会生成相同的ID。
- 当两个子图存在相同路由时,后注册的子图路由会复用先注册的ID,导致NavController无法区分两个子图中的同名目标。
- 从第二个子图的"b"导航到"c"时,NavController会尝试找到对应ID的回退栈条目,但当前回退栈属于第二个子图上下文,无法匹配到第一个子图中注册的"c"的ID,因此抛出异常。
解决方案
不需要强制全局唯一的路由,但需要保证子图内的路由在全局范围内可区分,最直接的方式是给子路由添加父图前缀:
navigation(route = "a", startDestination = "a/b") { composable("a/b") { Button(onClick = { navController.navigate("a/c") }) { Text("ab") } } composable("a/c") { Button(onClick = { navController.navigate("a/b") }) { Text("ac") } } } navigation(route = "x", startDestination = "x/b") { composable("x/b") { Button(onClick = { navController.navigate("x/c") }) { Text("xb") } } composable("x/c") { Button(onClick = { navController.navigate("x/b") }) { Text("xc") } } }
这样每个子路由都有唯一的全局标识,NavController可以准确识别目标所属的子图,避免ID冲突导致的崩溃。
内容的提问来源于stack exchange,提问作者radekholy24
相关产品推荐
相关产品推荐

