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);
}

 

 

 

 

 

 

 

 

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