Android序列化

2019-06-18  本文已影响0人  VitaAin

序列化(Serialization):将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

二进制序列化保持类型保真度,这对于在应用程序的不同调用之间保留对象的状态很有用。例如,通过将对象序列化到剪贴板,可在不同的应用程序之间共享对象。您可以将对象序列化到流、磁盘、内存和网络等等。远程处理使用序列化“通过值”在计算机或应用程序域之间传递对象。

简单地说,
“序列化”就是将运行时的对象状态转换成二进制,然后保存到流、内存或者通过网络传输给其他端。

Android中序列化有两种方式:SerializableParcelable


Serializable(JAVA自带)

Serializable 是 Java 提供的序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作。

使用:

使目标对象实现 Serializable 接口,并声明一个 serialVersionUID 即可。
(不声明serialVersionUID也可以实现序列化,但会对反序列化过程产生影响,后面做介绍。)

private static final long serialVersionUID = 8711368828010083044L;
示例:

以序列化到文件为例,借助 ObjectOutputStream 和 ObjectInputStream:

// 序列化过程
User user = new User(0, "Tom", true); // (id, name, isMale)
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();

// 反序列化过程
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
// user 与 newUser 内容完全一样,但并不是同一个对象
User newUser = (User) in.readObject();
in.close();
serialVersionUID:

serialVersionUID 是用来辅助序列化和反序列化过程的,原则上序列化后的数据中的 serialVersionUID 只有和当前类的 serialVersionUID 相同才能够正常地被反序列化。
serialVersionUID 工作机制:序列化的时候会把当前类的 serialVersionUID 写入序列化的文件中(或其他介质),当反序列化的时候系统回去检测文件中的 serialVersionUID ,看它是否和当前类的 serialVersionUID 一致,如果一致就说明序列化的类的版本和当前类的版本是相同的,就可以成功反序列化;否则就说明当前类和序列化的类相比发生了某些变换,比如成员变量的数量、类型可能发生了改变,此时是无法正常序列化的,会报如下错误:

java.io.InvalidClassException: Main; local class incompatible: 
stream classdesc serialVersionUID = 87113688280100830474, local class serialVersionUID = 8711368828010083043. 

一般来说,需要手动指定 serialVersionUID 的值,也可以让IDE根据当前类的结构自动去生成它的hash值,这样序列化和反序列化时两者的 serialVersionUID 时相同的,因此可以正常进行反序列化。

注意

Parcelable(Android专用)

Parcelable 也是一个接口,只要实现这个接口,一个类的对象就可以实现序列化并可以通过 Intent 和 Binder 传递。

示例:
public class User implements Parcelable {
  public int userId;
  public String userName;
  public boolean isMale;
  public Book book;

  public User(int userId, String userName, boolean isMale) {
    this.userId = userId;
    this.userName = userName;
    this.isMale = isMale;
  }

  public int describeContents() {
    return 0;
  }

  public void writeToParcel(Parcel out, int flags) {
    out.writeInt(userId);
    out.writeString(userName);
    out.writeInt(isMale ? 1 : 0);
    out.writeParcelable(book, 0);
  }

  public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
    public User createFromParcel(Parcel in) {
      return new User(in);
    }

    public User[] newArray(int size) {
      return new User[size];
    }
  };

  private User(Parcel in) {
    userId = in.readInt();
    userName = in.readString();
    isMale = in.readInt() == 1;
    book = in.readParcelable(Thread,currentThread().getContextClassLoader();
  }
}
Parcel

Parcel 内部包装了可序列化的数据,可以在 Binder 中自由传输。

Parcelable 序列化过程中需要实现序列化、反序列化和内容描述功能。

Parcelable 方法说明

系统已经提供了很多实现了 Parcelable 接口的类,它们都是可以直接序列化的,比如 Intent、Bundle、Bitmap 等,List、Map 也可以序列化,前提是它们里面的每个元素都是可序列化的。


Serializable 和 Parcelale 对比

两者都能实现序列化,并且都可用于 Intent 间的数据传递。

Android开发中,应首选 Parcelable。
Parcelable 主要用在内存序列化上,通过 Parcelable 将对象序列化到存储设备中或者将对象序列化后通过网络传输也都是可以的,但这个过程会稍显复杂,因此在这两种情况下建议使用 Serializable。

上一篇 下一篇

猜你喜欢

热点阅读