美文网首页Android学习笔记
浅谈Serializable和Parcelable

浅谈Serializable和Parcelable

作者: 小波_po | 来源:发表于2018-12-07 15:30 被阅读1次

一、作用

两者都是用于对象的序列化成二进制的流,便于在intent或bundle中传输。

二、区别

1. Serializable

Serializable是java的序列化接口,核心实现是ObjectOutPutStream.writeObject()进行序列化,ObjectInputStream.readObject()进行反序列化。

serialVersionUID
可在序列化的类中定义serialVersionUID,用static和final修饰,用于在反序列化中验证类版本的差异。

  • 如果不定义serialVersionUID,系统会声明个默认值,当类发生变化后,serialVersionUID将会被系统重新计算赋值,反序列化时,如果前后serialVersionUID不一致,将会crash,抛出InvalidClassException错误。
  • 如果定义serialVersionUID,尽管序列化后类发生变化,由于前后serialVersionUID一致,反序列化时也会尽最大的程度复原,如果复原失败一样会抛出InvalidClassException错误。

在Android Serializable 的Api注释中有段说明:针对Android N以上版本的设备时,为了保证对之前版本的兼容性,强烈建议显示的定义serialVersionUID,而不是由系统默认赋值。

2. Parcelable

Parcelable是Android特有的序列化接口,核心实现是通过parcel的读写操作进行序列化,里面的方法是Native方法。

  • 使用Serializable会频繁进行IO操作,开销很大,在Android平台上,Parcelable多用于内存序列化,如IPC进程间通信。

三、实现Parcelable步骤

public class Student implements Parcelable {

    private int id;
    private String name;
    private boolean isBoy;

    private Student(Parcel in) {
        id = in.readInt();
        name = in.readString();
        isBoy = in.readByte() != 0;
    }

    public static final Creator<Student> CREATOR = new Creator<Student>() {
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeInt(id);
        parcel.writeString(name);
        parcel.writeByte((byte) (isBoy ? 1 : 0));
    }
}

实现Parcelable必须实现describeContents()writeToParcel(Parcel parcel, int i)方法。还需要创建个Parcelable.Creator接口的成员,用于进行反序列化操作。

3.1 describeContents()

方法返回当前对象的内容描述,如果含有文件描述符,则返回1,一般默认返回0。

 /**
     * Describe the kinds of special objects contained in this Parcelable
     * instance's marshaled representation. For example, if the object will
     * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)},
     * the return value of this method must include the
     * {@link #CONTENTS_FILE_DESCRIPTOR} bit.
     *  
     * @return a bitmask indicating the set of special object types marshaled
     * by this Parcelable object instance.
     */
    public @ContentsFlags int describeContents();
3.2 writeToParcel(Parcel, int)

在这方法进行序列化,falg默认为0;如果需要对象作为返回值返回,则值为1,这样不能立即释放资源。

 /**
     * Flatten this object in to a Parcel.
     * 
     * @param dest The Parcel in which the object should be written.
     * @param flags Additional flags about how the object should be written.
     * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
     */
    public void writeToParcel(Parcel dest, @WriteFlags int flags);
3.3 Parcelable.Creator
 /**
     * Interface that must be implemented and provided as a public CREATOR
     * field that generates instances of your Parcelable class from a Parcel.
     */
    public interface Creator<T> {
        /**
         * Create a new instance of the Parcelable class, instantiating it
         * from the given Parcel whose data had previously been written by
         * {@link Parcelable#writeToParcel Parcelable.writeToParcel()}.
         * 
         * @param source The Parcel to read the object's data from.
         * @return Returns a new instance of the Parcelable class.
         */
        public T createFromParcel(Parcel source);
        
        /**
         * Create a new array of the Parcelable class.
         * 
         * @param size Size of the array.
         * @return Returns an array of the Parcelable class, with every entry
         * initialized to null.
         */
        public T[] newArray(int size);
    }

createFromParcel ():反序列化,创建原始序列化对象
newArray ():反序列化,创建原始序列化对象的数组
内部通过Parcel的read方法实现。

成员也需实现Parcelable才能保证序列化的完整
如果Student不实现Parcelable,那么School实现序列化的成员不包括Student

public class School implements Parcelable {

    private String name;
    private Student student;

    private School(Parcel in) {
        name = in.readString();
        student = in.readParcelable(Student.class.getClassLoader());
    }

    public static final Creator<School> CREATOR = new Creator<School>() {
        @Override
        public School createFromParcel(Parcel in) {
            return new School(in);
        }

        @Override
        public School[] newArray(int size) {
            return new School[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeParcelable(student, i);
    }
}

student = in.readParcelable(Student.class.getClassLoader())在反序列化时,需要获取当前线程的成员类的加载器,否则会报找不到该类的错误。

相关文章

网友评论

    本文标题:浅谈Serializable和Parcelable

    本文链接:https://www.haomeiwen.com/subject/xcdthqtx.html