序列化 Parcelable

  • Parcelable 是 Android 的进程/组件间高性能序列化协议,主要用于把对象写入 Parcel,在 组件间传递Intent/Bundle)、跨进程通信(Binder/AIDL)、状态保存(如部分系统回调)中使用。
  • 在现代 Android(含 API 35+)里,仍然推荐:组件间传递优先用 Parcelable(性能/体积/平台原生),而不是 Java Serializable

按“使用目的”划分(互斥、穷尽)

  • 组件内/进程内传递
    • Activity/Service/BroadcastReceiver 之间通过 Intent.putExtra()Bundle.putParcelable() 传递对象
    • Fragment 参数(arguments)或导航参数(底层也常走 Bundle
  • 跨进程通信(IPC)
    • Binder 事务中传输参数/返回值(AIDL 支持 Parcelable 类型)
    • 注意:跨进程的 Parcelable 更强调稳定性与版本兼容(字段增减策略)
  • 状态保存与恢复
    • 一些系统/框架场景会要求把状态写入 Parcel(例如自定义 View.BaseSavedState 体系)
    • 这里的 Parcelable 更像“状态快照”,字段一般更精简

按“实现方式”划分

  • 手写实现(原生接口)
    • 实现 ParcelablewriteToParcel()describeContents()、以及 CREATOR
    • 优点:可控、无需额外插件;缺点:样板代码多、易错(读写顺序/类型)
  • Kotlin @Parcelize(推荐主流方式)
    • Kotlin 插件生成 Parcelable 实现,减少样板代码
    • 优点:开发效率高、错误率低;缺点:需要 Kotlin/插件配置,某些复杂场景仍需自定义 Parceler
  • 自动代码生成/编译期工具链(广义)
    • @Parcelize 外,也可能用自研/三方生成器(但在新项目里一般不如 @Parcelize 直接)

按“数据结构类型”划分(你在业务里会遇到的几类)

  • 纯值对象(POJO/数据类)
    • val id: Long, val name: String 等:最适合 Parcelable
  • 包含集合/嵌套对象
    • List<Parcelable>Map、嵌套 data class:可行,但要关注体积和深度
  • 包含大对象/资源句柄
    • 如大 Bitmap、大数组、文件内容:原则上不建议直接塞进 Parcel(Binder 事务大小/内存抖动)
    • 更推荐传 Uri/文件路径/数据库 key,然后在目标端加载
  • 包含 Binder/FD 等“特殊资源”
    • 某些类型需要 describeContents() 返回 CONTENTS_FILE_DESCRIPTOR(少见,但属于严格语义点)

Parcel 的读写契约

  • Parcel 本质是按顺序写入的二进制流:写的顺序 = 读的顺序(这是最常见 bug 源)
  • CREATOR.createFromParcel(Parcel) 用于反序列化;newArray 用于数组创建
  • ClassLoader:反序列化嵌套类型时可能需要正确的 ClassLoader(尤其在多模块/动态加载场景)

Serializable 的对比(实践结论)

  • 性能:Parcelable 通常明显更快、更省内存(避免反射/对象图开销)
  • 兼容性:Serializable 版本演进依赖 serialVersionUID 等;Parcelable 则是你自己维护读写顺序与默认值策略
  • 结论:Android 组件传参/IPC 场景优先 Parcelable;仅在非常低频、简单、非性能敏感的场景才考虑 Serializable

工程建议(面向 API 35+ 的现代写法)

  • 传参“瘦身”:只传必要字段(id、token、uri),避免传大对象
  • 演进策略:新增字段时放在末尾读取;读取时为旧版本缺失字段提供默认值(手写实现时尤其重要)
  • 测试:对 Parcel 循环(write→read)做单元测试,能快速发现顺序/类型错误

如果你希望我更贴近你的项目实践,我可以按同样的 MECE 框架再补一层:分别给出 @Parcelize 的最小示例手写实现示例、以及 AIDL 里如何声明/传递 Parcelable(都按 minSdk 35 的语境组织)。

package demo

import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import androidx.activity.ComponentActivity
import kotlinx.parcelize.Parcelize

@Parcelize
data class User(
  val id: Long,
  val name: String
) : Parcelable

class SenderActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val user = User(id = 1L, name = "Alice")
    val intent = Intent(this, ReceiverActivity::class.java).apply {
      putExtra("extra_user", user)
    }
    startActivity(intent)
    finish()
  }
}

class ReceiverActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val user: User? = intent.getParcelableExtra("extra_user", User::class.java)
    // user?.id / user?.name
  }
}
  • 这是最常见的 Parcelable 场景:Activity 之间通过 Intent 传一个 data class
  • 关键点是 Kotlin 的 @Parcelize:编译期自动生成 writeToParcelCREATOR
  • 读取用 API 33+ 的新签名:getParcelableExtra(key, User::class.java)(与你的 minSdk=35 完全匹配)

要让这段代码可编译,你的模块需要启用 Kotlin Parcelize 插件(Gradle 里加 plugins { id("kotlin-parcelize") } 或同等配置)。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容