Android 进程间通信的数据容器详解
Parcelable容器| 类别 | 具体类型 | 备注 |
|---|---|---|
| 基本类型 | int, long, double, float, boolean, byte, char, short |
- |
| 基本类型数组 | int[], long[], byte[]等 |
- |
| 字符串 | String, CharSequence, String[] |
- |
| Parcelable 对象 | Parcelable及其子类 |
推荐:高效 |
| Parcelable 列表 | ArrayList<? extends Parcelable> |
必须用专用方法 |
| Parcelable 数组 | Array<? extends Parcelable> |
必须用专用方法 |
| Serializable 对象 | Serializable |
不推荐,性能差 |
| Bundle | 嵌套 Bundle | - |
| 特殊类型 | Size, SizeF, ParcelFileDescriptor |
- |
List<Parcelable>或 Map等,必须使用对应的专用方法。
发送端:
val bundle = Bundle().apply {
putString("name", "张三")
putInt("age", 28)
putParcelableArrayList("books", booksArrayList)
}
intent.putExtra("data_bundle", bundle)
接收端:
val bundle = intent.getBundleExtra("data_bundle")
val name = bundle.getString("name")
val age = bundle.getInt("age", 0)
服务端:
override fun handleMessage(msg: Message) {
val bundle = msg.data
val replyBundle = Bundle().apply { putString("reply", "ok") }
msg.replyTo?.send(Message.obtain().apply { data = replyBundle })
}
客户端:发送 Message 时通过 msg.data设置 Bundle,并设置 msg.replyTo接收回复。
服务端:
override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
return Bundle().apply { putParcelableArrayList("list", resultList) }
}
客户端:
val result = contentResolver.call(uri, "METHOD", null, requestBundle)
val list = result?.getParcelableArrayList<Book>("list", Book::class.java)
| 你的变量类型 | 进 Bundle 的方法 | 取出的方法 |
|---|---|---|
ArrayList<Book> |
putParcelableArrayList(key, list) |
getParcelableArrayList(key, Book::class.java) |
Array<Book> |
putParcelableArray(key, array) |
getParcelableArray(key, Book::class.java) |
List<Book>(编译时) |
先转 ArrayList(list)再用上面方法 |
同 ArrayList |
putParcelable(key, list)→ 类型不匹配,因为 putParcelable期望单个对象
putParcelableArray(key, arrayList)→ 类型不匹配,因为期望数组
将可空 List<Book>?直接传给期望 Collection<out Book>的 Java 方法 → 需要 list?.let { ArrayList(it) }处理可空并转为可变集合
Bundle 内部通过 writeToParcel序列化对象,集合的序列化逻辑和单对象不同。putParcelableArrayList、putParcelableArray专门处理集合的写入和类型标记,保证反序列化回到正确类型。
使用 Kotlin @Parcelize最便捷(需在公共库中):
@Parcelize
data class Book(val title: String, val author: String) : Parcelable
Book.aidl文件声明从 API 33 开始,不带 Class<T>参数的获取方法被弃用,推荐显式传入类信息。
| 旧方法(弃用) | 新方法(API 33+) |
|---|---|
bundle.getParcelableArrayList<Book>("key") |
bundle.getParcelableArrayList("key", Book::class.java) |
bundle.getParcelable<Book>("key") |
bundle.getParcelable("key", Book::class.java) |
bundle.getParcelableArray("key") |
bundle.getParcelableArray("key", Book::class.java) |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
bundle.getParcelableArrayList("key", Book::class.java)
} else {
@Suppress("DEPRECATION")
bundle.getParcelableArrayList("key")
}
TransactionTooLargeException。大文件应传递 URI 或文件路径List?要处理空值,且转为 ArrayList 才能放入 Bundlebundle.setClassLoader()putParcelableArrayList/ putParcelableArrayClass<T>规避弃用至此,你已掌握 Android 中最基础、最通用的 IPC 方式。