Anroid Parcelable 与 Serializable 序列化比较

一、Android 中常用的序列化

Parcelable

  • 1、占内存小,因为没有字段属性、编码等额外信息
  • 2、在 Android IPC 中序列化和反序列化速度快
  • 3、存储数据以基本数据类型为单元,所有数据使用基本类型存储,引用类型存储(除 String)之外,会存储类名,字符类型会提供长度标记
  • 序列化和反序列化过程复杂,手动实现读和写,还需要借助Parcel,必要时设置ClassLoader

Serializable

  • 数据可读性好相对较好
  • 存储对象数据时会保留字段名和字段类型
  • 占用内存空间大
  • 序列化反序列化比较耗时,相比 Parcelable 只通过反射 new 对象,Serializable 字段反射也很频繁
  • 序列化和反序列化过程简单,基本调用api就完成

二、序列化大小测试

定义一个类,同时支持 Parcelable 和 Serializable,当然,你也可以单独实现

java 复制代码
public class ARect implements Parcelable , Serializable {
    public int left;
    public int top;
    public int right;
    public int bottom;
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ARect r = (ARect) o;
        return left == r.left && top == r.top && right == r.right && bottom == r.bottom && TextUtils.equals(name,r.name);
    }

    @Override
    public int hashCode() {
        int result = left;
        result = 31 * result + top;
        result = 31 * result + right;
        result = 31 * result + bottom;
        result = result +name!=null?name.hashCode():0;
        return result;
    }

    public int describeContents() {
        return 0;
    }
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(left);
        out.writeInt(top);
        out.writeInt(right);
        out.writeInt(bottom);
        out.writeString(name);
    }

    public static final Parcelable.Creator<ARect> CREATOR = new Parcelable.Creator<ARect>() {
        /**
         * Return a new rectangle from the data in the specified parcel.
         */
        public ARect createFromParcel(Parcel in) {
            ARect r = new ARect();
            r.readFromParcel(in);
            return r;
        }

        /**
         * Return an array of rectangles of the specified size.
         */
        public ARect[] newArray(int size) {
            return new ARect[size];
        }
    };


    public void readFromParcel(Parcel in) {
        left = in.readInt();
        top = in.readInt();
        right = in.readInt();
        bottom = in.readInt();
        name = in.readString();
    }

}

序列化代码

java 复制代码
        ARect aRect = new ARect();
        aRect.left = 10;
        aRect.top = 10;
        aRect.bottom = 100;
        aRect.right = 100;
        aRect.name = "1H1";

        RandomAccessFile aRaf = new RandomAccessFile("/sdcard/arect_p.dat","rw");
        RandomAccessFile bRaf = new RandomAccessFile("/sdcard/arect_s.dat","rw");


       //Parcelable序列化
        Parcel parcel = Parcel.obtain();
        parcel.setDataPosition(0);
        parcel.writeString("Aa");
        parcel.writeInt(2);
        parcel.writeParcelable(aRect, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        byte[] buf  = parcel.marshall();
    
        aRaf.write(baos.toByteArray());


      // Serializable 序列化
        ByteArrayOutputStream baos  = new ByteArrayOutputStream();
        ObjectOutputStream outputStream = new ObjectOutputStream(baos);
        outputStream.writeUTF("Aa");
        outputStream.writeInt(2);
        outputStream.writeObject(aRect);
        bRaf.write(baos.toByteArray());
        outputStream.close();

        aRaf.close();
        bRaf.close();

Parcelable 反序列化

Parcelable 存储格式短,读取顺序时强约束,占内存也很小,不需要查找数据类型和字符编码。

ini 复制代码
Parcel dst = Parcel.obtain();
dst.unmarshall(buffer, 0, buffer.length);
dst.setDataPosition(0);
String Aa = dst.readString();
int b = dst.readInt();
ClassLoader classLoader = ARect.class.getClassLoader();
ARect dstRect = dst.readParcelable(classLoader);

Serilizable 反序列化

这种方法很成熟,本篇就贴出来了。

效果

Parcelable序列化后的文件编码

Serializable序列化后的文件编码

存储特点:

  • 【1】Parcelable 依赖顺序,数据分为 "字符类型" + "byte 类型", 而 Serializable 基本上会保留字段名,字段类型,甚至 utf 编码
  • 【2】Parcelable 中字符串类名最终都会以 char 类型存储,存储 String 或 Char 类型时会在开头往前推,第四个字节时字符串或 Char 的长度
  • 【3】Parcelable 数据包中,如果最后一位时字符类型,那么会在后面 00 00 00 后面在添加 FF FF FF,以此表示数据包结束。(这句本来是测过,懒得发图了)

可见,随着字段的增多,Parcelable 优势将更加明显

性能测试

其实从数据I/O和反射次数就能明显的看出Parcelable更胜一筹,这里就不测试了。

RPC、IPC、持久化

Serializable、protobuf 经常被用于RPC和持久化存储,而Parcelable因为能够减少数据量,特别适合跨进程通信,无论是Binder、LocalSocket还是ShareMemory都能使用Parcelable跨进程数据传输(IPC)。

Parcelable 持久化问题

对于Parcelable是不是支持持久化问题,很多博客说"不能"持久化,其实本篇可以看到其本身是支持持久化的,显然"不能"这个表述是不恰当的。

那到底应不应该使用Parcelable持久化呢?

作为使用过Parcelable持久化方式的开发者,我的总结如下:

  • 正常情况下是可以使用Parcelable进行持久化的,但是要避免字段类型、读写顺序变更
  • Parcelable持久化不支持字段属性(字段类型、字段名称)记忆,因此,恢复方式只能依赖Android平台
  • Parcelable不支持字段裁剪,如果你想删除某个之前的字段,可能会导致反序列化失败。
  • Parcelable缺少版本机制,因此需要自行记录和设置更新机制
  • 和Serializable一样,不适合频繁I/O

总结

本篇我们通过手动实践,对我们常见的数据对象进行比较系统的认识,Parcelable不仅性能上更优秀,其次也可以支持持久化,不过建议存储一些数据量较大(如配置项)、字段不会裁剪、类型不会变化的数据。

相关推荐
也无晴也无风雨30 分钟前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
SRC_BLUE_1732 分钟前
SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based
android·网络安全·adb·less
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
无尽的大道4 小时前
Android打包流程图
android
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
镭封5 小时前
android studio 配置过程
android·ide·android studio
夜雨星辰4875 小时前
Android Studio 学习——整体框架和概念
android·学习·android studio