天天看点

Serializable、Parcelable详解

Serializable

这是java提供的序列化接口,实现这个接口的类就能够进行序列化了,所有的实现细节都是系统自动规定、完成的,序列化/反序列化实例如下:

// 序列化过程。方便查看逻辑,没有添加try/catch
UserBean userBean = new UserBean("wk",);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File(KuPathUtil.getImageDir(), "cache.txt")));
out.writeObject(userBean);
out.close();

// 反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(KuPathUtil.getImageDir(), "525.txt")));
UserBean userBean = (UserBean) in.readObject();
in.close();
           

serialVersionUID是用来标识当前版本的,比如你的app在1.0版本的时候把UserBean对象序列化到rom中了,app升级到2.0后,UserBean类的结构发生了变化,此时再把rom中的文件反序列化成对象,肯定就会出错了。

反序列化的时候会先检查serialVersionUID是否一致,如果不一致就会报错;如果id一致,但是类结构发生了轻微变化(比如增/删了一两个字段),也可以最大限度地反序列化,如果类结构发生了毁灭性的改变,就无法反序列化了;如果没有serialVersionUID字段,理论上是无法反序列化的,但是用AS开发时,没有id字段也可以反序列化,猜测是AS自动加的。

Parcelable

Serializable序列化和反序列化需要大量的I/O操作,开销比较大,而很多时候我们只需要序列化一个对象,让其作为一个通信媒介。Parcelable就是Android专门提供的序列化接口,需要我们自己实现序列化和反序列化的接口。实际上,系统也提供了很多已经实现了Parcelable接口的类,比如Intent、Bundle、Bitmap等。

下面看一个标准的Parcelable接口实现:

public class UserBean implements Parcelable {
    private int mAge;
    private boolean isOld;
    private String mName;
    private Car mCar;
    private String[] mArray;
    private List<Car> mList;

    // 读取序列化内容,转换成该类对象
    private UserBean(Parcel in) {
        mAge = in.readInt();
        // 读取Bool值
        isOld = in.readByte() != ;
        mName = in.readString();
        // 读取对象。需要用当前线程的上下文类加载器
        mCar = in.readParcelable(Thread.currentThread().getContextClassLoader());
        mArray = in.createStringArray();

        // 读取List。需要List中的对象实现了Parcelable,参数list也不能为空
        mList = new ArrayList<>();
        in.readTypedList(mList, Car.CREATOR);

    }

    // 反序列化
    public static final Parcelable.Creator<UserBean> CREATOR = new Parcelable.Creator<UserBean>() {
        @Override
        public UserBean[] newArray(int size) {
            // 序列化内容转换成数组
            return new UserBean[size];
        }

        @Override
        public UserBean createFromParcel(Parcel source) {
            // 序列化内容转换成对象
            return new UserBean(source);
        }
    };

    @Override
    public int describeContents() {
        // 在类UNIX系统中,一切皆是文件,文件描述符就是操作文件的数据结构,获取到文件描述符可以完成所有文件相关的操作
        // 文件描述符的作用如此之大,为了防止异常,需要禁止在Bundle传输Parcel时包含文件描述符,所以在Bundle中传递Parcelable数据时,该值必须返回0
        return ;
    }

    @Override
    // 序列化。注意序列化和反序列化的顺序一定要一致
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mAge);
        dest.writeByte((byte) (isOld ?  : ));
        dest.writeString(mName);
        dest.writeParcelable(mCar, flags);
        dest.writeStringArray(mArray);
        dest.writeTypedList(mList);
    }
}