Android Parcel

Parcel 是 Android 特有的数据序列化反序列化机制,不同于 Serializable,Parcel 主要用作进程间通信,是跨进程传输对象的工具。

Parcelable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
Interface for classes whose instances can be written to and restored from a Parcel.
Classes implementing the Parcelable interface must also have a non-null static field called
CREATOR of a type that implements the Parcelable.Creator interface.
*/
public interface Parcelable {

public void writeToParcel(Parcel dest, @WriteFlags int flags);

public interface Creator<T> {
public T createFromParcel(Parcel source);
public T[] newArray(int size);
}
}

Parcelable 是一个接口,实现该接口的类可以存储在 Parcel 对象中。

需要注意的是: 实现 writeToParcel() 和 createFromParcel() 时读写字段的顺序要保持一致,否则会出现 Parcel android.os.Parcel@60522f8: Unmarshalling unknown type code 3801137 at offset 244 错误。

Parcel

Parcel(包裹) 主要用作进程间通信,而不是序列化。效率高又节省内存。

Parcel 支持读写的常见数据类型整理如下:

  • Primitives 基本数据类型
  • Primitive Arrays 基本数据类型的数组
  • Parcelables 实现 Parcelable 接口的类
  • Bundles 一种 Key-Value 形式的数据包装类
  • Binder
  • FileDescriptor
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* Container for a message (data and object references) that can be sent through an IBinder.
* Parcel is not a general-purpose serialization mechanism.
* This class is designed as a high-performance IPC transport.
*/
public final class Parcel {
private long mNativePtr; // used by native code
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];

private static native int nativeDataSize(long nativePtr);
//... 一些列 native 方法

public final static Parcelable.Creator<String> STRING_CREATOR
= new Parcelable.Creator<String>() {
public String createFromParcel(Parcel source) {
return source.readString();
}
public String[] newArray(int size) {
return new String[size];
}
};

public static Parcel obtain() {
final Parcel[] pool = sOwnedPool;
synchronized (pool) {
Parcel p;
for (int i=0; i<POOL_SIZE; i++) {
p = pool[i];
if (p != null) {
pool[i] = null;
if (DEBUG_RECYCLE) {
p.mStack = new RuntimeException();
}
p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
return p;
}
}
}
return new Parcel(0);
}

public final void recycle() {
if (DEBUG_RECYCLE) mStack = null;
freeBuffer();

final Parcel[] pool;
if (mOwnsNativeParcelObject) {
pool = sOwnedPool;
} else {
mNativePtr = 0;
pool = sHolderPool;
}

synchronized (pool) {
for (int i=0; i<POOL_SIZE; i++) {
if (pool[i] == null) {
pool[i] = this;
return;
}
}
}
}
}

Parcel 创建过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private Parcel(long nativePtr) {
init(nativePtr);
}

//变量赋值
private void init(long nativePtr) {
if (nativePtr != 0) {
mNativePtr = nativePtr;
mOwnsNativeParcelObject = false;
} else {
mNativePtr = nativeCreate();
mOwnsNativeParcelObject = true;
}
}

private static native long nativeCreate();

进入 Native 层:

~\frameworks\base\core\jni\android_os_Parcel.cpp

1
2
3
4
5
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel();
return reinterpret_cast<jlong>(parcel);
}

~\frameworks\native\libs\binder\Parcel.cpp

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
Parcel::Parcel()
{
initState();
}

void Parcel::initState()
{
mError = NO_ERROR;
mData = 0;
mDataSize = 0;
mDataCapacity = 0;
mDataPos = 0;
mObjects = NULL;
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
mOwner = NULL;
mOpenAshmemSize = 0;

// racing multiple init leads only to multiple identical write
if (gMaxFds == 0) {
struct rlimit result;
if (!getrlimit(RLIMIT_NOFILE, &result)) {
gMaxFds = (size_t)result.rlim_cur;
//ALOGI("parcel fd limit set to %zu", gMaxFds);
} else {
ALOGW("Unable to getrlimit: %s", strerror(errno));
gMaxFds = 1024;
}
}
}
参数 含义
mData 表示一块内存,用来存储 IPC 数据
mDataSize mData 已存储的数据大小
mDataCapacity mData 指示的内存大小
mDataPos 数据写入或读取的内存开始位置
mObjects 表示一块内存(该对象主要用作 Binder 记录相关对象的引用)
mObjectsSize mObjects 已存储的数据大小
mObjectsCapacity mObjects 指示的内存大小

参考

[1] Binder 基石-Parcel