Android Binder中Parcel数据结构Java篇

320 阅读2分钟

通俗版讲解:Parcel 是什么?

你可以把 Parcel 想象成一个「快递包裹」,它专门用来在 Android 不同进程之间传递数据。比如 App 要给系统服务发请求,或者两个 App 要通信,数据都得打包成 Parcel 的格式。


核心知识点(一句话版)

  1. ​跨层协作​
    Java 层的 Parcel 只是个「空壳」,真正干活的都是 Native 层(C++)的代码,通过 JNI 调用。
  2. ​对象池优化​
    频繁创建/销毁 Parcel 太费资源,所以系统用「缓存池」管理。比如池子里有 6 个现成的 Parcel,用完了就还回来,不够用再新建。
  3. ​支持的数据类型​
    能打包基础类型(int 等)、数组、Bundle、Binder 对象等。但要注意:List/Map 这类容器如果没指定泛型,可能出问题。

关键流程拆解

1️⃣ 获取 Parcel 对象(借包裹)

  • ​操作​​:Parcel.obtain()

  • ​内部逻辑​​:

    • 先看缓存池(sOwnedPool)有没有闲置的 Parcel,有就直接拿
    • 没有就 new 一个,并让它的内部指针指向 Native 层新创建的 C++ Parcel 对象

2️⃣ 回收 Parcel(还包裹)

  • ​操作​​:recycle()

  • ​内部逻辑​​:

    • 如果缓存池没满,就把 Parcel 放回去标记为「可复用」
    • 如果池子满了,就彻底销毁(包括 Native 层的内存释放)

3️⃣ 数据读写(装货/卸货)

  • ​写 int​​:Java 的 writeInt() → 调用 Native 的 writeInt32()

  • ​读 int​​:Java 的 readInt() → 调用 Native 的 readInt32()

  • ​写 Binder​​(如 Service):

    • Java 的 Binder 对象 → 通过 JNI 找到对应的 Native 层 Binder(JavaBBinder 或 BpBinder)
    • 把 Native Binder 的指针写入 Parcel
  • ​读 Binder​​:

    • 从 Parcel 读取出 Native Binder 指针 → 转成 Java 的 Binder 或 BinderProxy 对象

为什么这样设计?

  • ​性能​​:Native 层操作内存更高效,适合高频的 IPC 通信
  • ​复用​​:对象池减少频繁创建/销毁带来的开销
  • ​兼容性​​:Java 层提供友好的 API,底层用 C++ 实现复杂逻辑

举个栗子 🌰

假设你要通过快递(Binder)寄一本书(数据):

  1. ​打包​​:用 Parcel 把书装好(writeInt、writeBinder)
  2. ​寄送​​:Binder 驱动把包裹送到对方进程
  3. ​拆包​​:对方用 Parcel 把书取出(readInt、readBinder)
  4. ​回收​​:包裹盒子(Parcel)还到快递站,下次继续用