Activity - Parcel/Parcelable/Bun

2023-04-26  本文已影响0人  行走中的3卡

1. 基本概念

Parcel 中文为包裹
Parcelable 中文为可包裹
Bundle 中文为捆绑
Binder 中文为粘合剂

Parcelable 和 Bundle 对象可跨进程边界使用,
例如与 IPC/Binder 事务之间,带有 intent 的 Activity 之间等,
还可以用来存储跨配置更改的瞬时状态。

注意:Parcel 不是通用序列化机制,绝不能将任何 Parcel 数据存储在磁盘上或通过网络发送。
Parcel 需要调用 natvie 方法读写数据

Parcel/Parcelable/Bundle 均在package android.os 包里
Parcel 可通过 IBinder 传递 (数据)
Parcelable 封装 Parcel;
Bundle 实现 Parcelable

1.1 Parcel

Container for a message (data and object references) that can be sent through an IBinder.
可通过 IBinder 发送的消息(数据和对象引用)的容器。

//Parcel.java
public final class Parcel {
    private static native int nativeWriteInt(long nativePtr, int val);
    private static native int nativeWriteLong(long nativePtr, long val);
    
    public final void writeInt(int val) {nativeWriteInt()...}
    public final void writeLong(long val) {nativeWriteLong()...}

1.2 Parcelable

Interface for classes whose instances can be written to and restored from a {@link Parcel}.
实例可写入的类的接口 并从 {@link Parcel} 恢复

//Parcelable.java;
public interface Parcelable {
    public void writeToParcel(Parcel dest, @WriteFlags int flags);
    public void writeToParcel(Parcel dest, @WriteFlags int flags);

    public interface Creator<T> {
        public T createFromParcel(Parcel source); 
        public T[] newArray(int size);
        
}

1.3 Bundle

A mapping from String keys to various {@link Parcelable} values
从字符串键到各种 {@link Parcelable} 值的映射

public final class Bundle extends BaseBundle implements Cloneable, Parcelable {

}

BaseBundle
A mapping from String keys to values of various types.
从字符串键到各种类型的值的映射.

public class BaseBundle {
    ArrayList<CharSequence> getCharSequenceArrayList(@Nullable String key) {..}
    public boolean[] getBooleanArray(@Nullable String key) {...}
    byte[] getByteArray(@Nullable String key) {...}
    void writeToParcelInner(Parcel parcel, int flags) {..}
    void readFromParcelInner(Parcel parcel) {...}
    
}

2. 在 Activity 之间发送数据

2.1 使用 Bundle

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

例如:

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

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

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

2.2 使用 Parcelable

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

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

3. 在进程之间发送数据

在进程之间发送数据与在 Activity 之间发送数据类似。
不过,在进程之间发送时,我们建议不要使用自定义 Parcelable。

如果您将一个自定义 Parcelable 对象从一个应用发送到另一个应用,
则需要确保发送和接收的应用上都存在版本完全相同自定义类
通常情况下,这可能是在两个应用中都会使用的通用库。
如果您的应用尝试向系统发送自定义 Parblelable,则可能会发生错误,因为系统无法对其不了解的类进行解组。

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

对于 savedInstanceState 的具体情况,应将数据量保持在较小的规模,
因为只要用户可以返回到该 Activity,系统进程就需要保留所提供的数据(即使 Activity 的进程已终止)。
我们建议您将保存的状态保持在 50k 数据以下。

参考文献:
https://developer.android.com/guide/components/activities/parcelables-and-bundles?hl=zh-cn

上一篇下一篇

猜你喜欢

热点阅读