Parcelable 和 Bundle

ParcelableBundle 对象可跨进程边界使用,例如与 IPC/Binder 事务之间,带有 intent 的 Activity 之间等,还可以用来存储跨配置更改的瞬时状态。本页提供了有关使用 ParcelableBundle 对象的建议和最佳实践。

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

在 Activity 之间发送数据

当应用创建要在 startActivity() 中使用的 Intent 对象以启动新的 Activity 时,应用可以使用 putExtra() 方法传入参数。

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

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

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

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

在某些情况下,您可能需要跨 Activity 传递复杂对象或在界面状态中保留这些对象。 在这种情况下,自定义类应实现 Parcelable。对于现代 Kotlin 和 Jetpack Compose 应用,建议的方法是使用 @Parcelize 注解。这会自动生成在使用 Bundle 时安全处理数据所需的序列化逻辑。这与使用 rememberSaveable 处理数据的方法相同。 如需详细了解如何使用 @Parcelize, 请参阅 Parcelable 实现生成器

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

在进程之间发送数据

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

例如,应用可能会使用 AlarmManager 类设置闹钟,并在闹钟 intent 中使用自定义 Parcelable。当闹钟响起时,系统会修改 intent 的 Bundle 额外内容以添加重复计数。 此修改可能会导致系统从额外内容中剥离自定义 Parcelable。反过来,这种剥离可能会导致应用在收到修改后的闹钟 intent 时崩溃,因为应用希望收到已不再存在的额外数据。

Binder 事务缓冲区的大小固定有限,目前为 1MB,由进程中正在处理的所有事务共享。 由于此限制是进程级别而不是 Activity 级别的限制,因此这些事务包括应用中的所有 binder 事务,例如 startActivityrememberSaveable(在后台使用 onSaveInstanceState)以及与系统的任何互动。超出大小限制时,系统会抛出 TransactionTooLargeException

对于使用 rememberSaveable 保存状态的特定情况,数据量应保持较小,因为系统进程需要保留提供的数据,只要用户可以返回到该 Activity(即使该 Activity 的进程被终止也是如此)。我们建议您将保存的状态保持在 50KB 以下。

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