Android之Parcel和Parcelable

相對於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++ 層。

 

調用過程

  1. 獲取Parcel 對象:通過obtain()靜態方法,
  2. 數據的存儲和讀取:通過writeXXX()和 readXXX()實現,
  3. 數據序列化和反序列化:marshall()和 unmarshall()
  4. 回收資源:通過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);
}

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章