Serializable、Parcelable 的简介及区别

来源:互联网 发布:万方数据库中检索字段 编辑:程序博客网 时间:2024/06/09 23:46

前言

众所周知,在 Android 开发中,我们无法将对象的引用传给 Activity 或者 Fragment,我们需要将对象放到一个Intent或者Bundle里面,然后再进行传递,所以我们就需要用到对象的序列化。将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。Android 中序列化的方式有两种,一种是 Serializable(Java 自带),一种是 Parcelable(Android 专用)。

Serializable

Serializable 是 Java 提供的一个序列化接口,是一个空接口,为对象提供序列化和反序列化的操作。可以通过 IO 流可轻松进行序列化和反序列化。
serialVersionUID 是用来辅助序列化和反序列化过程的。

private static final long serialVersionUID = 1L;

原则上反序列后的数据中的 serialVersionUID 只有和当前类的 serialVersionUID 相同才能正常的被反序列化。注意以下两点:

  • 静态成员变量属于类不属于对象,不参与序列化过程
  • 用 transient 关键则标记的成员变量不参与序列化过程
public transient String like;Bundle setbundle=new Bundle();Person person=new Person(111,"姓名","篮球");setbundle.putSerializable("person",person);if (bundle.containsKey("person")) {    Person p= (Person)bundle.getSerializable("person");    Logger.e("id="+p.getUserid());    Logger.e("name="+p.getName());    Logger.e("like="+p.getLike());}打印出来like为null            

Parcelable

Parcelable 也是一个接口,Parcelable 是 Android 上的序列化方式,比较适合用在 Android 开发上。示例如下:

public class Student implements Parcelable {    public int sId;    public String name;    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel dest, int flags) {        dest.writeInt(this.sId);        dest.writeString(this.name);    }    public Student() {    }    protected Student(Parcel in) {        this.sId = in.readInt();        this.name = in.readString();    }    public static final Parcelable.Creator<Student> CREATOR = new Parcelable.Creator<Student>() {        @Override        public Student createFromParcel(Parcel source) {            return new Student(source);        }        @Override        public Student[] newArray(int size) {            return new Student[size];        }    };    public Student(int sId, String name) {        this.sId = sId;        this.name = name;    }    public int getsId() {        return sId;    }    public void setsId(int sId) {        this.sId = sId;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}

Parcelable 接口定义在封送/解封送过程中混合和分解对象的契约。Parcelable 接口的底层是 Parcel 容器对象。Parcel 类是一种最快的序列化/反序列化机制,专为 Android 中的进程间通信而设计。该类提供了一些方法来将成员容纳到容器中,以及从容器展开成员。在序列化过程中需要实现的功能有序列化、反序列化和内容描述。序列化功能由 writeToParcel 方法完成,最终是通过 Parcel 中的一系列 write 方法来完成。反序列化由 CREATOR 来完成,其内部标明了如何创建序列化对象和数组,并通过 Parcel 的一系列 read 方法来完成反序列化过程。内容描述功能由 describeContents 方法来完成,几乎在所有情况下这个方法都应该返回 0,仅当当前对象中存在文件描述符时返回 1。系统为我们提供了许多实现了 Parcelable 接口的类,它们都是可以直接序列化对的,比如 Intent、Bundle、Bitmap 等,同时 List 和 Map 也可以序列化,前提是它们里面的每一个元素都可以序列化。

Serializable、Parcelable 的区别

  • Serializable 使用了反射,虽然使用简单但大量的 io 操作使得开销大、效率慢。序列化的时候创建许多的临时对象,容易触发垃圾回收。
  • Parcelable 实现原理是将一个完整的对象进行分解;效率高;主要用在内存序列化上。
  • 通过 Parcelable 将对象序列化到存储设备上或者通过网络传输也都是可以的,但是这个过程复杂,这两种情况建议还是用 Serializable。
  • Parcelable 不能使用在要将数据存储在磁盘上的情况,因为 Parcelable 不能很好的保证数据的持续性在外界有变化的情况下。不推荐使用Parcelable进行数据持久化。尽管 Serializable 效率低点,但此时还是建议使用 Serializable。

通过 Bundle 传递注意对象大小

Intent 中的 Bundle 是在使用 Binder 机制进行数据传递的,能使用的 Binder 的缓冲区是有大小限制的(有些手机是2M),而一个进程默认有16个 binder 线程,所以一个线程能占用的缓冲区就更小了(以前做过测试,大约一个线程可以占用128KB)。如果超过大小会报“The Binder transaction failed because it was too large.”这类 TransactionTooLargeException 异常。
因此,使用 Intent 在 Activity 之间传递 List 和 Bitmap 对象是有风险的。

0 0