相對於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);
}