使用Android Compose SafeArgs导航时遭遇kotlinx.serialization多态序列化异常
Android Compose SafeArgs导航时遭遇kotlinx.serialization多态序列化异常
嘿,我之前也碰到过几乎一模一样的问题,当时在SafeArgs里传带自定义日期类的Parcelable时卡了好久,咱们一步步来拆解问题,搞定它!
首先得搞清楚为啥会报这个错:kotlinx序列化的多态机制有个要求——当你序列化非密封基类(比如这里的Parcelable接口)的子类时,必须显式把这个子类注册到序列化模块里。虽然你的ParcelableDate已经加了@Serializable和自定义序列化器,但Parcelable本身是个开放接口,不是密封类,所以序列化框架没法自动识别它的子类序列化器,这就导致了导航跳转时的序列化异常。
解决方案1:显式注册序列化模块
这是最直接有效的办法,我们需要把ParcelableDate手动注册到kotlinx序列化的模块中:
步骤1:创建自定义序列化模块
在你的项目里新建一个object或者单独的文件,定义全局的序列化模块:
import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic val AppSerializersModule = SerializersModule { // 注册Parcelable的子类ParcelableDate polymorphic(Parcelable::class) { subclass(ParcelableDate::class) } }
步骤2:全局配置序列化模块
在你的Application类里初始化Json时指定这个模块,让整个App都用这个配置:
import android.app.Application import kotlinx.serialization.Json class MyNormativeApp : Application() { override fun onCreate() { super.onCreate() Json { serializersModule = AppSerializersModule // 可选:忽略未知字段,避免因字段变动导致的序列化失败 ignoreUnknownKeys = true } } }
步骤3:开启SafeArgs的kotlin序列化支持
在你的app级build.gradle(或build.gradle.kts)里添加配置,让SafeArgs使用kotlinx序列化来处理导航参数:
android { // ... 其他已有的配置(比如compose、viewBinding等) navigation { safeArgs { enableExperimentalKotlinSerialization = true } } }
解决方案2:替换线程不安全的SimpleDateFormat
顺带提个小坑:你代码里用的SimpleDateFormat不是线程安全的,在Compose这种多线程的UI环境下很容易出现奇怪的bug,建议换成Java 8+的DateTimeFormatter(或者AndroidX的ThreeTenABP库兼容低版本):
import java.time.Instant import java.time.format.DateTimeFormatter import java.util.Date import java.util.Locale // 定义全局的线程安全格式化器 private val dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault()) // 在ParcelableDate的序列化/反序列化里替换成这个 override fun ParcelableDate.write(parcel: Parcel, flags: Int) { val isoString = dateFormatter.format(date.toInstant()) parcel.writeString(isoString) } override fun create(parcel: Parcel): ParcelableDate { val isoString = parcel.readString() val date = Date.from(Instant.from(dateFormatter.parse(isoString))) return ParcelableDate(date ?: Date()) }
额外检查点
- 确认你的
ModelExerciseEvent和ParcelableDate都正确添加了@Parcelize和@Serializable注解,没有遗漏 - 如果
ModelExerciseEvent里还有其他自定义的Parcelable子类,也要记得把它们注册到AppSerializersModule里
内容来源于stack exchange




