注册

了解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

  1. Parcelable只是对内存操作,并没有序列化成正在的二进制;而Serializable会被流操作对象序列化成二进制字节数据;
  2. Serializable中使用了大量的反射和临时变量,在性能上低于Parcelable;
  3. Serializable在使用时是传入到流对象进行序列化和反序列化处理,而Parcelable都是在内部实现序列化和反序列化,Parcelable更加灵活;

4.总结

根据上述分析,得出下面结论:

  1. Parcelable只适合在Android中进行IPC通信时使用,也建议优先采用,可提高性能;但是需要注意,因为Parcelable是对内存的操作,所以大量对象数据时,可能会造成内存溢出。
  2. Serializable可以在IPC、本地存储、网络传输中都可以使用,但是因为使用了大量反射和临时变量,相对于Parcelable在性能上稍逊。

0 个评论

要回复文章请先登录注册