Jetpack Compose给navController传编码字符串参数报IllegalArgumentException
问题原因
你触发异常的核心原因是:序列化生成的JSON字符串中包含/、"、:等URI保留特殊字符,Jetpack Navigation的路由匹配逻辑基于URI解析规则,这些特殊字符会被识别为URI分隔符,导致你拼接的导航路由与提前注册的detail/{user}路由规则无法匹配,最终抛出找不到目标目的地的异常。
解决方案
方案1:对JSON字符串做URL编码转义
这是修改成本最低的兼容方案,仅需修改导航传参与参数解析两处逻辑:
- 导航前对序列化后的JSON做URL编码,转义所有特殊字符:
ListScreen() { user -> val json: String = Json.encodeToString(user) // 编码转义特殊字符 val encodedJson = URLEncoder.encode(json, StandardCharsets.UTF_8.toString()) navController.navigate("detail/$encodedJson") }
- 解析参数时先做URL解码,再反序列化为User对象:
composable(route = "detail/{user}", arguments = listOf( navArgument("user") { type = NavType.StringType } )) { backStackEntry -> val encodedJson = requireNotNull(backStackEntry.arguments).getString("user")!! // 先解码再反序列化 val json = URLDecoder.decode(encodedJson, StandardCharsets.UTF_8.toString()) val user = Json.decodeFromString<User>(json) DetailScreen(user = user) }
方案2:自定义NavType实现直接传递对象
如果需要更简洁的调用方式,可以自定义适配User类型的NavType,无需手动处理序列化、编码逻辑:
- 首先定义自定义NavType:
val UserNavType = object : NavType<User>(isNullableAllowed = false) { override fun get(bundle: Bundle, key: String): User? { return Json.decodeFromString(bundle.getString(key) ?: return null) } override fun parseValue(value: String): User { return Json.decodeFromString(value) } override fun put(bundle: Bundle, key: String, value: User) { bundle.putString(key, Json.encodeToString(value)) } }
- 修改路由注册时的参数类型配置:
composable(route = "detail/{user}", arguments = listOf( navArgument("user") { type = UserNavType } )) { backStackEntry -> val user = requireNotNull(backStackEntry.arguments).getParcelable<User>("user")!! DetailScreen(user = user) }
- 导航时直接拼接编码后的JSON即可,也可以配合官方类型安全导航扩展进一步简化调用。
注意:如果你的项目使用Navigation Compose 2.8.0及以上版本,已经原生支持
@Serializable类型参数的自动序列化传递,无需手动自定义NavType,仅需引入类型安全导航依赖即可使用。
内容的提问来源于stack exchange,提问作者Thracian
相关产品推荐
相关产品推荐

