Parcelable 和 Bundle

ParcelableBundle 对象旨在跨进程边界使用,例如用于 IPC/Binder 事务、具有 intent 的 activity 之间,以及用于在配置发生更改时存储瞬时状态。本页面提供了有关使用 ParcelableBundle 对象的建议和最佳做法。

注意Parcel 不是通用序列化机制,切勿将任何 Parcel 数据存储在磁盘上或通过网络发送。

在 Activity 之间发送数据

当应用创建 Intent 对象以在 startActivity(android.content.Intent) 中用于启动新 activity 时,应用可以使用 putExtra(java.lang.String, java.lang.String) 方法传入参数。

以下示例代码段演示了如何执行此操作。

Kotlin

val intent = Intent(this, MyActivity::class.java).apply {
    putExtra("media_id", "a1b2c3")
    // ...
}
startActivity(intent)

Java

Intent intent = new Intent(this, MyActivity.class);
intent.putExtra("media_id", "a1b2c3");
// ...
startActivity(intent);

操作系统会将 intent 的基础 Bundle 打包。然后,操作系统会创建新的 activity,将数据解封,并将 intent 传递给新的 activity。

我们建议您使用 Bundle 类在 Intent 对象上设置操作系统已知的基元。Bundle 类针对使用 Parcel 进行编组和解组进行了高度优化。

在某些情况下,您可能需要一种机制来跨 activity 发送复合对象或复杂对象。在这种情况下,自定义类应实现 Parcelable,并提供相应的 writeToParcel(android.os.Parcel, int) 方法。它还必须提供一个名为 CREATOR 的非 null 字段,用于实现 Parcelable.Creator 接口,其 createFromParcel() 方法用于将 Parcel 转换回当前对象。如需了解详情,请参阅 Parcelable 对象的参考文档。

通过 intent 发送数据时,您应注意将数据大小限制为几 KB。发送过多数据可能会导致系统抛出 TransactionTooLargeException 异常。

在进程之间发送数据

在进程之间发送数据与在 Activity 之间发送数据类似。不过,在进程之间发送时,我们建议您不要使用自定义 Parcelable。如果您将自定义 Parcelable 对象从一个应用发送到另一个应用,则需要确保发送和接收应用上存在自定义类的同一版本。通常,这可能是在两个应用中使用的通用库。如果您的应用尝试向系统发送自定义 Parcelable,则可能会发生错误,因为系统无法解组其不知道的类。

例如,应用可以使用 AlarmManager 类设置闹钟,并对闹钟 intent 使用自定义 Parcelable。当闹钟响起时,系统会修改 intent 的 extra Bundle 以添加重复计数。这种修改可能会导致系统从 extra 中删除自定义 Parcelable。这种剥离继而可能会导致应用在收到修改后的警报 intent 时崩溃,因为应用预计接收的额外数据已不存在。

Binder 事务缓冲区具有有限的固定大小(目前为 1MB),由进程中的所有正在进行的事务共享。由于此限制是进程级(而不是 activity 级)的,因此这些事务包括应用中的所有 binder 事务,例如 onSaveInstanceState、startActivity 以及与系统的任何交互。超过大小限制时,系统会抛出 TransactionTooLargeException。

对于 savedInstanceState 的具体情况,应尽量减少数据量,因为只要用户可以导航回该 activity,系统进程就需要持有提供的数据(即使 activity 的进程已终止)。我们建议您将保存的状态保持在 5 万个数据以内。

注意:在 Android 7.0(API 级别 24)及更高版本中,系统会抛出 TransactionTooLargeException 作为运行时异常。 在较低版本的 Android 中,系统仅在 logcat 中显示警告。