一、Parcelable的作用
Parcelable是Android为我们提供的序列化接口。
什么是序列化呢?简单说就是将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行数据传输,反序列化就是从二进制流(序列)转换为对象的过程。
为什么要序列化呢?
1)永久性保存对象,保存对象的字节序列到本地文件中;
2)通过序列化对象在网络中传递对象;
3)通过序列化在进程间传递对象。
二、Parcelable和Serializable的比较
Parcelable的性能比Serializable好,因为Serializable在反射过程中会频繁GC。所以在内存间数据传输时推荐使用Pacelable,如Activity间的数据传输;Serializable可将数据持久化方便保存,Parcelable在不同android版本可能不同,而且在外界有变化的情况下不能很好的保证数据的持续性,所以在需要保存或网络传输数据时选择Serializable。
三、Parcelable的使用
1、implements Parcelable接口
2、重写writeToParcel()方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中
3、重写describeContents()方法,内容接口描述方法,默认返回0即可,只针对一些特殊的需要描述信息的对象需要返回1。
4、实例化静态内部对象CREATOR实现接口Parcelable.Creator,public static final Parcelable.Creator<T> CREATOR
其中public static final一个都不能少,内部对象CREATOR的名称也不能改变,必须全部大写。需要重写Creator接口中的两个方法:
T createFromParcel(Parcel in):实现从Parcel容器中读取传递数据值,封装成Parcelable对象返回逻辑层。
T[] newArray(int size):创建一个类型为T、长度为size的数组,供外部类反序列化本类数组使用。
简而言之就是通过writeToParcel()方法将你的对象映射成Parcel对象,再通过createFromParcel()方法将Parcel对象映射成你的对象,也可以将Parcel看成是一个流,通过writeToParcel把对象写到流里面,再通过createFromParcel从流里读取对象,只不过这个读写过程需要你自己来实现,所以写的顺序和读的顺序必须一致。
四、Parcelable传递复杂对象
private byte byteData;
private short shortData;
private int intData;
private long longData;
private float floatData;
private double doubleData;
private char charData;
private boolean booleanData;
private String stringData;
private BigDecimal bigDecimalData;
private OuterEntity outerEntity;
private List<OuterEntity> outerList;
private InnerEntity innerEntity;
private List<InnerEntity> innerList;
private Map<String, OuterEntity> map1;
private Map<Integer, List<OuterEntity>> map2;
Parcelable要将如上定义的数据类型序列化,其中bigDecimalData、map1、map2三个属性序列化的时候是不做处理的,需要自己手动增加一下。
1)writeToParcel()方法:
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeByte(byteData);
dest.writeInt((int) shortData);
dest.writeInt(intData);
dest.writeLong(longData);
dest.writeFloat(floatData);
dest.writeDouble(doubleData);
dest.writeInt((int) charData);
dest.writeByte((byte) (booleanData ? 1 : 0));
dest.writeString(stringData);
dest.writeString(bigDecimalData == null ? "0" : bigDecimalData.toString());
dest.writeParcelable(outerEntity, flags);
dest.writeTypedList(outerList);
dest.writeParcelable(innerEntity, flags);
dest.writeTypedList(innerList);
if (null != map1 && map1.size() > 0) {
dest.writeInt(map1.size());//先写入map的大小
for (Map.Entry<String, OuterEntity> entry : map1.entrySet()) {
dest.writeString(entry.getKey());
dest.writeParcelable(entry.getValue(), flags);
}
}
if (null != map2 && map2.size() > 0) {
dest.writeInt(map2.size());
for (Map.Entry<Integer, List<OuterEntity>> entry : map2.entrySet()) {
dest.writeInt(entry.getKey());
dest.writeTypedList(entry.getValue());
}
}
}
2)读出方法:
protected ParcelableEntity(Parcel in) {
byteData = in.readByte();
shortData = (short) in.readInt();
intData = in.readInt();
longData = in.readLong();
floatData = in.readFloat();
doubleData = in.readDouble();
charData = (char) in.readInt();
booleanData = in.readByte() != 0;
stringData = in.readString();
bigDecimalData=new BigDecimal(in.readString());
outerEntity = in.readParcelable(OuterEntity.class.getClassLoader());
outerList = in.createTypedArrayList(OuterEntity.CREATOR);
innerEntity = in.readParcelable(InnerEntity.class.getClassLoader());
innerList = in.createTypedArrayList(InnerEntity.CREATOR);
if (map1 == null) map1 = new HashMap<>();
int map1Size = in.readInt();
if (map1Size > 0) {
for (int i = 0; i < map1Size; i++) {
String key = in.readString();
OuterEntity value = in.readParcelable(OuterEntity.class.getClassLoader());
map1.put(key, value);
}
}
if (map2 == null) map2 = new HashMap<>();
int map2Size = in.readInt();
if (map2Size > 0) {
for (int i = 0; i < map2Size; i++) {
Integer key = in.readInt();
List<OuterEntity> value = in.createTypedArrayList(OuterEntity.CREATOR);
map2.put(key, value);
}
}
}
五、有继承关系的实体序列化
Parcelable序列化需要在最自层的实体类中实现Parcelable接口,并在最自层的实体类中把父类所有的属性都序列化;Serializable只需在最外层的父类实体类中实现Serializable接口。
protected ParcelableSubclassEntity(Parcel in) {
parentAge=in.readInt();
parentName=in.readString();
subclassAge = in.readInt();
subclassName = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(parentAge);
dest.writeString(parentName);
dest.writeInt(subclassAge);
dest.writeString(subclassName);
}
完整代码:https://github.com/ruxing1102/SerializationPractice/tree/master