Jetpack Compose Navigation传递带伴生对象的数据类参数报错问题
结论
直接通过savedStateHandle传递未做序列化处理的自定义数据类实例的方式不可行,你遇到的伴生对象类型不支持报错,本质是框架对存入参数的类型校验机制触发的,不存在专门的标记可以让框架直接忽略伴生对象,但是可以通过正确实现序列化的方式绕开这个问题,不需要改动伴生对象本身的代码。
报错核心原因
savedStateHandle底层基于Bundle实现存储,仅原生支持基础数据类型、字符串等系统默认可序列化类型,对于自定义类型,会递归校验其所有关联结构是否符合序列化要求。你传入的数据类没有实现合法的序列化接口时,框架扫描类结构时会识别到内部的伴生对象,而伴生对象是类级单例,不满足Bundle存储的类型要求,就会抛出你看到的异常:
java.lang.IllegalArgumentException: Object of type blablabla$Companion is not supported for navigation arguments.
可行实现方案(不使用共享ViewModel)
- 方案1:给数据类添加
@Parcelize注解实现Parcelable接口
Kotlin提供的@Parcelize注解会自动生成数据类主构造函数内声明字段的序列化逻辑,默认不会处理类内部的伴生对象,伴生对象里定义的常量、方法都不会被纳入序列化传递的范围,完全符合你不需要传递伴生对象内容的需求。代码示例:
实现完import android.os.Parcelable import kotlinx.parcelize.Parcelize @Parcelize data class YourBizData( val itemId: Long, val title: String, val content: String // 仅在此处声明需要传递的业务字段 ) : Parcelable { companion object { // 伴生对象内的代码不需要做任何修改,不会被序列化逻辑扫描 const val TYPE_NORMAL = 1 fun createEmpty() = YourBizData(0, "", "") } }Parcelable接口后,你原来的传参代码navController.currentBackStackEntry?.savedStateHandle?.set("arg", item)不需要修改,即可正常存入和读取数据类实例。 - 方案2:将数据类序列化为JSON字符串传递
如果你不想给数据类实现Parcelable接口,可以先把数据类实例转成JSON格式的字符串,再通过savedStateHandle存储——字符串是原生支持的存储类型,不会触发自定义类型校验,接收端拿到字符串后再反序列化为对应数据类即可。这种方式全程不会扫描类的伴生对象结构,不会触发对应异常。
补充说明
没有办法实现“连带伴生对象一同传递”的效果:伴生对象是类绑定的全局单例,不属于数据类实例的成员字段,本身不存在序列化存储的可能性。
内容的提问来源于stack exchange,提问作者Dmitri
相关产品推荐
相关产品推荐

