Android Kotlin跨应用传Parcelable报Class Not Found异常求助
问题根因
- 自定义Parcelable类路径不匹配:报错明确提示找不到类
com.example.Parcelable.User,但接收端定义的User类全限定名为com.example.receive.User。跨应用反序列化Parcelable时,系统会严格按照数据写入时的类全路径加载类,路径不一致直接触发ClassNotFound异常,系统会自动丢弃异常的Bundle数据,最终出现mParcelledData=null、mMap size=0、hasExtra("USER")返回false的现象。 - Intent配置错误:
ComponentName.unflattenFromString()要求入参格式为应用包名/目标Activity全类名,你只传入了接收端包名,解析出的组件信息无效,根本无法正确定位到接收端页面。- 同时设置显式组件和调用
Intent.createChooser()时,createChooser会生成新的选择器Intent,不会将原Intent携带的extras原封不动传给目标应用。 - 你设置的Intent类型为
text/plain,实际传递的是自定义Parcelable对象,数据类型和声明不匹配。
- Key不匹配风险:发送端用常量
USER_KEY存储数据,接收端硬编码字符串"USER"取值,如果USER_KEY的实际值不是"USER",即使数据正常传递也无法读取。 - 类加载器缺失:跨应用获取Bundle数据时,默认类加载器无法识别应用内自定义类,即使类路径一致也可能出现反序列化失败。
解决步骤
1. 统一两端Parcelable类配置(核心修复)
跨应用传递自定义Parcelable必须满足以下要求,否则必然出现反序列化失败:
- 发送端、接收端的User类包名、类名完全一致:发送端的User类必须也放在
com.example.receive包下,不能放在com.example.Parcelable包下。 - 两端User类的成员变量顺序、类型、名称完全一致,序列化逻辑完全一致:两端都需要开启
kotlin-parcelize插件,使用相同的@Parcelize注解配置。
注意:Android 13(API 33)及以上版本对跨应用传递自定义Parcelable做了严格限制,默认禁止非系统类的跨进程反序列化,直接传自定义Parcelable兼容性极差。
2. 修复发送端Intent逻辑
如果明确要跳转到指定应用的指定页面,不要使用createChooser,修正后发送端代码如下:
btnSendData1.setOnClickListener { // 正确构造目标组件:第一个参数是接收端包名,第二个参数是接收端目标Activity全类名 val targetComponent = ComponentName( "com.example.receive", "com.example.receive.MainActivity" ) val intent = Intent(Intent.ACTION_SEND).apply { type = "text/plain" component = targetComponent // 统一key,直接用字符串"USER",和接收端取值key保持一致 putExtra("USER", User("Ahmer", "28")) } startActivity(intent) }
3. 修复接收端数据解析逻辑
解析时给Bundle指定正确的类加载器,同时适配高版本API:
@SuppressLint("SetTextI18n") private fun handleSendText(intent: Intent) { val extras = intent.extras if (extras != null) { // 给Bundle设置User类的类加载器,解决跨应用类加载失败问题 extras.classLoader = User::class.java.classLoader if (extras.containsKey("USER")) { // 适配API33+的Parcelable读取方法 val user = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { extras.getParcelable("USER", User::class.java) } else { @Suppress("DEPRECATION") extras.getParcelable("USER") } if (user != null) { textView.text = "${user.name}${user.age}" } else { Toast.makeText(this, "数据解析失败", Toast.LENGTH_SHORT).show() } } else { Toast.makeText(this, "未找到对应Key的数据", Toast.LENGTH_SHORT).show() } } else { Toast.makeText(this, "Intent携带数据为空", Toast.LENGTH_SHORT).show() } }
4. (推荐)规避跨应用Parcelable兼容问题
跨应用直接传递自定义Parcelable版本兼容性差、适配成本高,更稳妥的方案是传递JSON字符串:
- 发送端:将User对象序列化为JSON字符串,通过
putExtra("USER_DATA", jsonString)传递 - 接收端:拿到字符串后通过Gson/Moshi等JSON框架反序列化为User对象
这种方案不需要两端类路径一致,也不存在类加载器、版本限制问题,兼容所有Android版本。
内容的提问来源于stack exchange,提问作者Ahmer Iqbal
相关产品推荐
相关产品推荐

