Bundle 是什么
Bundle 是 Android 中用于存储键值对数据 的容器类,本质上是一个 Map 结构,专门用于在不同组件之间传递轻量级数据。
常见使用场景(Activity ↔ Fragment 通信)
java
// Activity 向 Fragment 传递数据
Bundle bundle = new Bundle();
bundle.putString("user_name", "张三");
bundle.putInt("user_age", 20);
MyFragment fragment = new MyFragment();
fragment.setArguments(bundle); // 设置参数
// Fragment 中接收数据
Bundle args = getArguments();
String name = args.getString("user_name");
Bundle 能传递的数据类型
- 基本类型:String、int、boolean、float、long、double
- 数组和集合:String\[\]、ArrayList、ArrayList 等
- 实现了 Parcelable 或 Serializable 接口的对象
Binder 是什么
Binder 是 Android 中**跨进程通信(IPC)**的核心机制,是 Linux 内核中的一个驱动程序,也是 Android 系统底层最重要的 IPC 方式。
核心特点
- 底层机制:基于 Linux 内核的 Binder 驱动
- 跨进程:用于不同进程之间的通信
- C/S 架构:通过 IBinder 接口,客户端调用服务端暴露的方法
- 安全性:Android 为每个应用分配独立的 UID,Binder 内核驱动进行权限校验
典型使用场景
- ActivityManagerService(AMS)与 App 进程通信
- startService() / bindService() 与 Service 通信
- AIDL(Android Interface Definition Language)定义跨进程接口
Bundle 与 Binder 的区别
| 维度 | Bundle | Binder |
|---|---|---|
| 层级 | 应用层 API | 系统底层机制(内核驱动) |
| 作用 | 数据容器,传递数据 | 跨进程通信的"桥梁" |
| 进程范围 | 同进程内传递 | 主要用于跨进程通信 |
| 数据大小 | 较小(官方建议 < 1MB,实际几百 KB 就可能触发 TransactionTooLargeException) |
理论上无严格限制(但受 Binder 缓冲区 1MB 限制) |
| 实现原理 | 内部使用 ArrayMap 存储键值对 |
基于 Linux 内核的内存映射(mmap) |
| 使用复杂度 | 简单,直接 put/get | 复杂,需要定义 AIDL 接口、实现 Stub 等 |
| 性能 | 同进程内高效 | 跨进程有额外序列化/反序列化开销 |
Bundle 与 Binder 的联系
虽然两者定位和层级完全不同,但在实际开发中紧密配合:
1. Bundle 底层依赖 Binder
当你调用 startActivity(intent) 时:
Intent 携带 Bundle → AMS(Binder 跨进程调用)→ 目标 Activity
这里的 Bundle 数据通过 Binder 机制跨进程传递到系统服务,再由系统服务分发到目标进程。
2. 数据序列化方式相通
Bundle 中传递自定义对象时,需要实现 Parcelable 接口。而 Parcelable 的 writeToParcel() 和 createFromParcel() 方法,底层正是通过 Parcel 进行序列化------Parcel 是 Binder 通信的数据载体。
java
// Parcelable 的 writeToParcel 方法
public void writeToParcel(Parcel out, int flags) {
out.writeString(name); // 写入 Parcel(Binder 的数据包)
out.writeInt(age);
}
3. 共同受 Binder 事务限制
Bundle 传递数据过大时会抛出 TransactionTooLargeException,根本原因是:Bundle 的数据最终要通过 Binder 驱动传输,而 Binder 内核缓冲区只有 1MB(且被所有并发事务共享)。
总结
Bundle 是"装数据的盒子",Binder 是"送盒子的快递系统"。 Bundle 负责打包数据,Binder 负责在进程间运送这个盒子。当 Activity 与 Fragment 在同进程内通信时,Bundle 直接传递;当涉及跨进程(如启动另一个 App 的 Activity)时,Bundle 的数据就需要 Binder 来运输。
延伸
Activity 与 Fragment 通信的其他方式
| 方式 | 适用场景 | 说明 |
|---|---|---|
setArguments(Bundle) |
初始化传参 | 官方推荐,Fragment 重建时参数不会丢失 |
| 接口回调 | Fragment → Activity 通信 | Fragment 定义接口,Activity 实现 |
ViewModel + LiveData |
共享数据 | 现代推荐方案,生命周期感知,自动处理配置变更 |
| 直接调用 | 不推荐 | 耦合度高,Fragment 不应直接持有 Activity 引用 |