了解Parcelable存在的意义
Parcelable是Google团队专门为Android设计的序列化类,那在Java中已经有了Serializable序列化为什么还需要Parcelable呢?我们接下来就通过阅读Parcelable的实现类和源码来比较它们的区别,建议先对Serializable序列化原理有一个了解。
1.实现类
我们看一个实现了Parcelable的实体类。
public class Person implements Parcelable {
private String name;
private int sex;
private int age;
private String phone;
protected Person(Parcel in) {
name = in.readString();
sex = in.readInt();
age = in.readInt();
phone = in.readString();
}
public static final Creator<Person> CREATOR = new Creator<Person>() {
@Override
public Person createFromParcel(Parcel in) {
return new Person(in);
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(sex);
dest.writeInt(age);
dest.writeString(phone);
}
}
describeContents()方法是默认实现,特殊情况才需要返回1,newArray(int size)方法也是默认实现就行。重点看createFromParcel()和writeToParcel()方法,见名知意writeToParcel()就是序列化方法,createFromParcel()是反序列化方法。不管是启动Activity时的传递对象还是AIDL中的使用,都是通过调用这两个方法来实现数据对象的序列化和反序列化。
2.源码分析
先分析序列化writeToParcel()方法,对数据的序列化操作都是通过传入的Parcel对象。
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(sex);
dest.writeInt(age);
dest.writeString(phone);
}
我们追踪写入String数据的进去看一下。
public final void writeString(@Nullable String val) {
writeString16(val);
}
继续深入。
public final void writeString16(@Nullable String val) {
mReadWriteHelper.writeString16(this, val);
}
调用了一个帮助类的方法,传入了自己和序列化数据。
public void writeString16(Parcel p, String s) {
p.writeString16NoHelper(s);
}
最终还是调用的Parcel方法。
public void writeString16NoHelper(@Nullable String val) {
nativeWriteString16(mNativePtr, val);
}
nativeWriteString16()是一个本地方法。
@FastNative
private static native void nativeWriteString16(long nativePtr, String val);
序列化到了这里也就追踪不下去了,那我们再看反序列化createFromParcel()方法。
public Person createFromParcel(Parcel in) {
return new Person(in);
}
对数据的操作也是通过Parcel对象。直接调用了Person有参构造方法,并传入了Parcel对象。
protected Person(Parcel in) {
name = in.readString();
sex = in.readInt();
age = in.readInt();
phone = in.readString();
}
我们也看下是如何读取String数据的。
public final String readString() {
return readString16();
}
再深入。
public final @Nullable String readString16() {
return mReadWriteHelper.readString16(this);
}
同样,还是调用了帮助类的方法,传入了自己。
public String readString16(Parcel p) {
return p.readString16NoHelper();
}
还是调用了Parcel对象的方法。
public @Nullable String readString16NoHelper() {
return nativeReadString16(mNativePtr);
}
再调用了本地方法。
@FastNative
private static native String nativeReadString16(long nativePtr);
反序列化也只能追踪到这里,会发现所有的操作都是通过Parcel类实现,但是序列化和反序列化的源码流程很简单,暴露给我们的过程很少,核心的数据处理都是采用的本地方法,会疑惑数据究竟存到哪里去了呢?其实是在本地开辟了一块共享内存,通过指针指向了这块内存,把数据存入了这里面。
3.Parcelable VS Serializable
- Parcelable只是对内存操作,并没有序列化成正在的二进制;而Serializable会被流操作对象序列化成二进制字节数据;
- Serializable中使用了大量的反射和临时变量,在性能上低于Parcelable;
- Serializable在使用时是传入到流对象进行序列化和反序列化处理,而Parcelable都是在内部实现序列化和反序列化,Parcelable更加灵活;
4.总结
根据上述分析,得出下面结论:
- Parcelable只适合在Android中进行IPC通信时使用,也建议优先采用,可提高性能;但是需要注意,因为Parcelable是对内存的操作,所以大量对象数据时,可能会造成内存溢出。
- Serializable可以在IPC、本地存储、网络传输中都可以使用,但是因为使用了大量反射和临时变量,相对于Parcelable在性能上稍逊。