一、作用
两者都是用于对象的序列化成二进制的流,便于在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())
在反序列化时,需要获取当前线程的成员类的加载器,否则会报找不到该类的错误。