IPC机制系列五 Parcelable接口

Parcelable接口

       Parcelable也是一个接口,只要实现这个接口,一个类的对象就可以实现序列化并可以通过Intent和Binder传递,下面的示例是一个典型的用法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class User implements Parcelable {

public int userId;
public String userName;
public boolean isMale;

public Book book;

public User(int userId, String userName, boolean isMale) {
this.userId = userId;
this.userName = userName;
this.isMale = isMale;
}


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


@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(userId);
dest.writeString(userName);
dest.writeByte((byte) (isMale ? 1 : 0));
dest.writeParcelable(book, 0);
}


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

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


protected User(Parcel in) {
userId = in.readInt();
userName = in.readString();
isMale = in.readInt() == 1;
book = in.readParcelable(Thread.currentThread().getContextClassLoader());
}

}

       Parcel内部包装了可序列化的数据,可以在Binder中自由传输,从上述代码中可以看出,在序列化过程中需要实现的功能有序列化、反序列化和内容描述,序列化功能由writeToParcel方法来完成,最终是通过Parcel中的一系列write方法来完成的,反序列化功能由CREATOR来完成,其内部标明了如何创建序列化对象和数组,并通过Parcel的一系列read方法来完成反序列化过程;内容描述功能由describeContents方法来完成,几乎在所有情况下这个方法都应该返回0,仅当当前对象中存在文件描述符时,此方法返回1。需要注意的是,在User(Parcel in)方法中,由于book是另一个可序列化对象,所以它的反序列化过程需要传递当前线程的上下文类加载器,否则会报无法找到类的错误。详细的方法说明参看下表:

方法 功能 标记位
createFromParcel(Parcel in) 从序列化后的对象中创建原始对象。
newArray(int size) 创建指定长度的原始对象数组。
User(Parcel in) 从序列化后的对象中创建原始对象。
writeToParcel(Parcel out , int flags) 将当前对象写入序列化结构中,其中flags标识有两种值:0或1(参见右侧标记位)。为1时标识当前对象需要作为返回值返回,不能立即释放资源,几乎所有情况都为0。 PARCELABLE_WRITE_RETURN_VALUE
describleContents 返回当前对象的内容描述,如果含有文件描述符,返回1(参见右侧标记位),否则返回0,几乎所有情况都返回0。 CONTENTS_FILE_DESCRIPTOR

       系统已经为我们提供了许多实现了Parcelable接口的类,它们都是可以直接序列化的,比如Intent、Bundle、Bitmap等,同时List和Map也可以序列化,前提是它们里面的每个元素都是可序列化的。

       既然 Parcelable 和Serializable都能实现序列化并且都可用于Intent间的数据传递,那么二者该如何选取呢? Serializable是Java中的序列化接口,其使用起来简单但是开销很大,序列化和反序列化过程需要大量I/O操作。而Parcelable是Andrord中的序列化方式,因此更适合用在Android平台上,它的缺点就是使用起来稍微麻烦点,但是它的效率很高,这是Android推荐的序列化方式,因此我们要首选Parcelable。Parcelable主要用在内存序列化上,通过Parcelable将对象序列化到存储设备中或者将对象序列化后通过网络传输也都是可以的,但是这个过程会稍显复杂,因此在这两种情况下建议使用Serializable。以上就是Parcelable和Serializable的区别。

参考资料:
《Android 开发艺术探索》任玉刚 第2章 2.3.2 Parcelable接口

Fork me on GitHub