Parcel 是什么?
你可以把 Parcel 想象成一个"快递包裹",它在 Android 的 Binder 通信机制中负责打包和运输数据。客户端把数据装进这个包裹,服务端收到后拆开包裹读取数据。
Parcel 能装什么?
- 基本类型:数字、布尔值等
- 字符串
- 数组
- 特殊对象:比如 Binder 代理对象、文件描述符
- 自定义对象(需要实现 Parcelable 接口)
Parcel 的工作原理(以寄快递为例):
-
打包数据(写操作)
-
比如要寄一个数字 123:
- 先检查包裹剩余空间是否够用,不够就扩容(类似快递员换个更大的箱子)
- 把数字按固定格式放进箱子的指定位置
- 记录当前打包位置,方便后续继续装货
-
-
运输数据
- 通过 Binder 驱动(类似物流系统)把包裹送到目的地
-
拆包数据(读操作)
- 服务端按照同样的顺序和格式从包裹里取出数据
- 每取一件货物,就更新当前位置标记
关键技术细节:
-
内存管理
- 采用 1.5 倍扩容策略:每次空间不足时,新空间 = 原大小 * 1.5
- 内存对齐:所有数据按 4 字节对齐存放(类似货架每格固定大小,方便快速存取)
-
对象传输
-
传输 Binder 对象时:
- 本地对象(如服务实体)会被标记为
BINDER_TYPE_BINDER - 远程对象(如服务代理)会被标记为
BINDER_TYPE_HANDLE
- 本地对象(如服务实体)会被标记为
-
驱动会自动转换本地/远程标识,实现跨进程对象引用
-
-
特殊处理
- 字符串传输:先写长度再写内容,末尾自动补零对齐
- 文件描述符传输:会特殊标记并处理跨进程传递
为什么重要?
- 高效的内存管理:通过智能扩容和对齐策略,兼顾内存使用效率和访问速度
- 安全的跨进程传输:自动处理复杂对象的序列化/反序列化,对开发者透明
- 统一的接口设计:一套 API 支持各种数据类型,简化开发
举个例子:
想象你要通过快递寄送一个装有手机和说明书的包裹:
- 手机(对象)需要特殊包装,贴上"易碎品"标签(类似 Binder 对象标记)
- 说明书(字符串)要折成固定大小的纸张(内存对齐)
- 快递员(Binder 驱动)会检查包裹大小,换合适的箱子(内存扩容)
- 收件人必须按相同顺序拆包,才能正确拿到物品(数据读取顺序一致)
这就是 Parcel 在 Binder 通信中扮演的角色,它让复杂的跨进程数据传递变得简单可靠。