版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/recordGrowth/article/details/86520500
Android 中序列化相关的接口有两个,这里分别对它们介绍一下
Serializable
这是 Java 提供的序列化接口,实现该接口的类就可以序列化和反序列化
Serializable 使用简单,但需要大量 I/O 操作,开销很大
serialVersionUID
如果没有显式定义 serialVersionUID,序列化也能成功,序列化运行时会根据这个类的很多方面计算出默认的 serialVersionUID
但显式定义 serialVersionUID 是确保反序列化成功的关键
为帮助我们更原滋原味地理解,摘录 Serializable 关于 serialVersionUID 的部分注释如下:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
* It is also strongly advised that explicit
* serialVersionUID declarations use the <code>private</code> modifier where
* possible, since such declarations apply only to the immediately declaring
* class--serialVersionUID fields are not useful as inherited members.
如果 serialVersionUID 不一样,会抛出异常 InvalidClassException,反序列化失败!
修改序列化过程
如果想修改系统默认的序列化和反序列化过程,可以重写下面的方法:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
Parcelable
这是 Android 提供的序列化接口,使用稍显麻烦但效率很高
只要实现这个接口,一个类的对象就能序列化并通过 Intent
和 Binder
传递
Android 中实现该接口的类有 Intent 、Bundle、Bitmap
摘录 Parcel
类的部分注释如下:
* Container for a message (data and object references) that can
* be sent through an IBinder.
* <p class="note">Parcel is <strong>not</strong> a general-purpose
* serialization mechanism. This class (and the corresponding
* {@link Parcelable} API for placing arbitrary objects into a Parcel) is
* designed as a high-performance IPC transport. As such, it is not
* appropriate to place any Parcel data in to persistent storage: changes
* in the underlying implementation of any of the data in the Parcel can
* render older data unreadable.</p>
可以看出,Parcelable
被设计用来进行高性能的 IPC
传输,多用于内存的序列化,不建议用在网络和持久化存储中
使用示例
一个实现 Parcelable
接口的最简单的类大致如下:
public class Sbingo666 implements Parcelable {
private int version;
private String name;
private int desc;
/**
* 返回当前对象的内容描述
* 如果含有文件描述符返回 1,否则返回 0
* 几乎所有情况都返回 0
*
* @return 0 或 1
*/
@Override
public int describeContents() {
return 0;
}
/**
* 序列化
*
* @param dest 当前对象正要写入的 Parcel
* @param flags 1 表示当前对象需要作为返回值返回,不能立即释放资源
* 几乎所有情况都为 0
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.version);
dest.writeString(this.name);
dest.writeInt(this.desc);
}
protected Sbingo666(Parcel in) {
this.version = in.readInt();
this.name = in.readString();
this.desc = in.readInt();
}
public static final Creator<Sbingo666> CREATOR = new Creator<Sbingo666>() {
/**
* 反序列化
* @param source 序列化后的对象
* @return 对象 Sbingo666
*/
@Override
public Sbingo666 createFromParcel(Parcel source) {
return new Sbingo666(source);
}
@Override
public Sbingo666[] newArray(int size) {
return new Sbingo666[size];
}
};
}
通过代码里的注释,这个类的结构还是很好理解的
需要注意:序列化和反序列化两个方法中的字段【读写顺序】要一致!
代码生成插件
实现 Parcelable
接口需要写很多格式化的代码,确实比较麻烦
好在有插件可以帮我们完成这个工作,插件如下:
安装后重启AS,使用这个插件就能一键生成这些格式化的代码啦!