相对于Parcel,我们更常接触到Parcelable,两个单词很相像,它们有什么区别吗?
- 相同点:两个都是专门为 Android 设计的系统类。
- Parcel 是一个实体类,用于进程间通讯,传递数据。
- Parcelable 是一个接口,用于Android 高性能序列化(详细请访问)
public final class Parcel {.....}
public interface Parcelable {.....}
在了解过Parcelable 是什么东西后,让我们认识一下Parcel 类。
在AIDL 自动生成的文件中,有以下示例代码:
// 添加书籍
@Override
public void addBook(com.test.aidl_demo.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0); // Book是自定义对象,实现了Parcelable接口
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
Parcel类
Parcel,原为“包裹、打包”之意,在Android中,Parcel是一个容器,主要用于存储序列化数据,然后可以通过Binder在进程间传递这些数据。传递数据类型包括:
- 原始数据类型(用各种对应的方法写入,比如writeInt()、writeFloat()等),
- Parcelable对象(如:writeParcelable()、writeParcelableCreator()等)
- IBinder对象的引用(如:writeStrongBinder() )
通过搜索代码发现(需要下载Andorid源码),Android 在Java-Jni-C 都有Parcel类,
- Java层:/frameworks/base/core/java/android/os/Parcel.java
- JNI 层:/frameworks/base/core/jni/android_os_Parcel.cpp
- C++层:/frameworks/native/libs/binder/Parcel.cpp
可以发现:Java 层代码只是一个封装代理,真正的实现在C++ 层。
调用过程
- 获取
Parcel 对象:
通过obtain()
静态方法, - 数据的存储和读取:通过
writeXXX()
和readXXX()
实现, - 数据序列化和反序列化:
marshall()
和unmarshall()
, - 回收资源:通过
recycle()方法
1、如何获取一个Parcel 对象?
在Parcel.java中:
// 默认初始化一个Parcel池,因为进程间频繁通讯,不断创建Parcel会损耗性能,因此采取了复用
private static final int POOL_SIZE = 6;
private static final Parcel[] sOwnedPool = new Parcel[POOL_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) { // 若parcel池有对象,复用该对象,同时把池中该位置的对象清空
pool[i] = null;
if (DEBUG_RECYCLE) {
p.mStack = new RuntimeException();
}
return p;
}
}
}
return new Parcel(0); // 若没有,则新建一个
}
// 以上方法,或许有人会问:
// 不是复用parcel池吗,为什么要清空某个位置的元素,新建后也没见加入池啊?
// 答案是recycle()方法!退出时会在该方法中,重新把parcel对象加入池子。后面会介绍
// ptr = pointer,即指针
private Parcel(long nativePtr) {
if (DEBUG_RECYCLE) {
mStack = new RuntimeException();
}
//Log.i(TAG, "Initializing obj=0x" + Integer.toHexString(obj), mStack);
init(nativePtr);
}
private void init(long nativePtr) {
if (nativePtr != 0) {
mNativePtr = nativePtr;
mOwnsNativeParcelObject = false;
} else {
mNativePtr = nativeCreate(); // 创建成功后,返回对象指针
mOwnsNativeParcelObject = true;
}
}
private static native long nativeCreate();
在JNI层(android_os_Parcel.cpp,下同):
static const JNINativeMethod gParcelMethods[] = {
......
// java 层方法,对应着JNI 层的实现方法
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
{"nativeDestroy", "(J)V", (void*)android_os_Parcel_destroy},
......
};
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel(); // 调用了Native层的类
return reinterpret_cast<jlong>(parcel); // C++里的强制类型转换符,把一个指针转换成一个整数
}
在Parcel.cpp 中
Parcel::Parcel()
{
initState();
}
void Parcel::initState()
{
mError = NO_ERROR;
mData = 0;
mDataSize = 0;
mDataCapacity = 0;
mDataPos = 0;
ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
mObjects = NULL;
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
mOwner = NULL;
}
2、数据的写入
在Parcel.java 中
public final void writeInt(int val) {
nativeWriteInt(mNativePtr, val);
}
private static native void nativeWriteInt(long nativePtr, int val);
在JNI 层中
static const JNINativeMethod gParcelMethods[] = {
......
{"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},
{"nativeWriteLong", "(JJ)V", (void*)android_os_Parcel_writeLong},
......
};
static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
const status_t err = parcel->writeInt32(val);
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
在Native 层中:
status_t Parcel::writeInt32(int32_t val)
{
return writeAligned(val);
}
template<class T>
status_t Parcel::writeAligned(T val) {
COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));
if ((mDataPos+sizeof(val)) <= mDataCapacity) {
restart_write:
*reinterpret_cast<T*>(mData+mDataPos) = val;
return finishWrite(sizeof(val));
}
status_t err = growData(sizeof(val));
if (err == NO_ERROR) goto restart_write;
return err;
}
status_t Parcel::finishWrite(size_t len)
{
mDataPos += len;
ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos);
if (mDataPos > mDataSize) {
mDataSize = mDataPos;
ALOGV("finishWrite Setting data size of %p to %zu", this, mDataSize);
}
return NO_ERROR;
}
status_t Parcel::growData(size_t len)
{
size_t newSize = ((mDataSize+len)*3)/2;
return (newSize <= mDataSize)
? (status_t) NO_MEMORY
: continueWrite(newSize);
}
3、如何回收一个Parcel 对象?
在Java 层(Parcel.java):
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;
}
}
}
}
private void freeBuffer() {
if (mOwnsNativeParcelObject) {
nativeFreeBuffer(mNativePtr);
}
}
private static native void nativeFreeBuffer(long nativePtr);
在JNI 层:
static const JNINativeMethod gParcelMethods[] = {
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
{"nativeFreeBuffer", "(J)V", (void*)android_os_Parcel_freeBuffer},
{"nativeDestroy", "(J)V", (void*)android_os_Parcel_destroy},
{"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
{"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall},
};
static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
parcel->freeData();
}
}
在Native 层:
void Parcel::freeData()
{
freeDataNoInit();
initState();
}
void Parcel::freeDataNoInit()
{
if (mOwner) {
//ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);
} else {
releaseObjects();
if (mData) free(mData);
if (mObjects) free(mObjects);
}
}
void Parcel::initState()
{
mError = NO_ERROR;
mData = 0;
mDataSize = 0;
mDataCapacity = 0;
mDataPos = 0;
ALOGV("initState Setting data size of %p to %zu", this, mDataSize);
ALOGV("initState Setting data pos of %p to %zu", this, mDataPos);
mObjects = NULL;
mObjectsSize = 0;
mObjectsCapacity = 0;
mNextObjectHint = 0;
mHasFds = false;
mFdsKnown = true;
mAllowFds = true;
mOwner = NULL;
}
void Parcel::releaseObjects()
{
const sp<ProcessState> proc(ProcessState::self());
size_t i = mObjectsSize;
uint8_t* const data = mData;
binder_size_t* const objects = mObjects;
while (i > 0) {
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
release_object(proc, *flat, this);
}
}
void release_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who)
{
switch (obj.type) {
case BINDER_TYPE_BINDER:
if (obj.binder) {
LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who);
}
return;
case BINDER_TYPE_WEAK_BINDER:
if (obj.binder)
reinterpret_cast<RefBase::weakref_type*>(obj.binder)->decWeak(who);
return;
case BINDER_TYPE_HANDLE: {
const sp<IBinder> b = proc->getStrongProxyForHandle(obj.handle);
if (b != NULL) {
LOG_REFS("Parcel %p releasing reference on remote %p", who, b.get());
b->decStrong(who);
}
return;
}
case BINDER_TYPE_WEAK_HANDLE: {
const wp<IBinder> b = proc->getWeakProxyForHandle(obj.handle);
if (b != NULL) b.get_refs()->decWeak(who);
return;
}
case BINDER_TYPE_FD: {
if (obj.cookie != 0) close(obj.handle);
return;
}
}
ALOGE("Invalid object type 0x%08x", obj.type);
}