Jetpack Compose类型安全导航传递可空Task数据类时无参数导航崩溃问题
我来帮你分析并解决这个问题,你遇到的崩溃是因为自定义NavType对null值的处理逻辑和类型安全导航框架的交互出现了冲突,导致框架错误地尝试序列化Task类的默认Companion对象(这个对象没有标记@Serializable,所以抛出了序列化异常)。
问题原因拆解
当你调用navController.navigate(TaskRoutes.AddTaskScreen)时,路由的task参数使用默认值null,但你的自定义NavType中把null值序列化为字符串"null"存入Bundle,在框架解析时,这个处理逻辑和类型安全导航的序列化流程产生了冲突,意外触发了对Task.Companion的序列化尝试。
解决方案
你可以通过调整自定义NavType的null值处理逻辑来解决这个问题,同时确保路由类的定义正确:
1. 修正CustomNavType的null值处理逻辑
把原来存入字符串"null"的逻辑改为直接存入null,或者当值为null时不向Bundle中添加该参数,这样框架就能正确识别null值,不会触发错误的序列化行为:
object CustomNavType { val TaskType = object : NavType<Task?>(isNullableAllowed = true) { private val taskSerializer = Task.serializer() override fun get(bundle: Bundle, key: String): Task? { // 当Bundle中没有对应key时,直接返回null return bundle.getString(key)?.let { Json.decodeFromString(taskSerializer, it) } } override fun parseValue(value: String): Task? { // 处理空字符串和"null"字符串,都返回null return if (value.isBlank() || value == "null") { null } else { Json.decodeFromString(taskSerializer, Uri.decode(value)) } } override fun put(bundle: Bundle, key: String, value: Task?) { // 仅当value不为null时才存入Bundle,null时不添加该参数 value?.let { bundle.putString(key, Json.encodeToString(taskSerializer, it)) } } override fun serializeAsValue(value: Task?): String { // null时返回空字符串,避免框架解析异常 return value?.let { Uri.encode(Json.encodeToString(taskSerializer, it)) } ?: "" } } }
2. 确保路由类的参数默认值正确配置
你的TaskRoutes.AddTaskScreen必须是带可空默认值的@Serializable数据类,这样无参数调用时才能正确生成task为null的路由实例:
@Serializable sealed class TaskRoutes { @Serializable data class AddTaskScreen(val task: Task? = null) : TaskRoutes() }
3. 验证修改效果
现在调用navController.navigate(TaskRoutes.AddTaskScreen)时,task参数会被正确解析为null,不会再触发序列化异常;调用navController.navigate(TaskRoutes.AddTaskScreen(task))时也能正常传递Task对象。
备注:内容来源于stack exchange,提问作者Ahmad Nasser

