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不仅性能上更优秀,其次也可以支持持久化,不过建议存储一些数据量较大(如配置项)、字段不会裁剪、类型不会变化的数据。

相关推荐
m0_748236119 分钟前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
Watermelo61722 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_7482489423 分钟前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_7482356135 分钟前
从零开始学前端之HTML(三)
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink6 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者7 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-8 小时前
验证码机制
前端·后端
燃先生._.9 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js