You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 19:06:33