Parcel

作者: gczxbb | 来源:发表于2018-05-18 22:47 被阅读45次

    Parcel创建

    构造方法私有
    静态方法Parcel#obtain和Parcel#obtain(long obj)创建。

    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();
                    }
                    return p;
                }
            }
        }
        return new Parcel(0);
    }
    

    sOwnedPool内部Parcel池,数组,可存储POOL_SIZE个Parcel,POOL_SIZE是6,从0开始遍历,找到数组中不空的位置,返回Parcel,置空该位置。
    数组池中全空,新建Parcel对象返回。参数是0。
    sOwnedPool池中存储的都是自己创建(nativeCreate)native层Parcel的Parcel,sHolderPool池存储的是传入native层指针的Parcel。
    Parcel构造方法触发Parcel#init初始化。

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

    若nativePtr是0,JNI#nativeCreate创建native层Parcel对象,返回mNativePtr指针。若nativePtr非0,将其他Java层Parcel存储的native层指针赋值mNativePtr。
    JNI#android_os_Parcel_create方法

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

    创建native层Parcel对象。

    因此,Java层Parcel对象引用native层Parcel的指针。

    Parcel#writeInt分析

    Parcel#writeInt方法

    public final void writeInt(int val) {
        nativeWriteInt(mNativePtr, val);
    }
    

    触发JNI#nativeWriteInt方法。

    static void android_os_Parcel_writeInt(JNIEnv* env, jclass clazz, jlong nativePtr, jint val) {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            const status_t err = parcel->writeInt32(val);
            if (err != NO_ERROR) {
                signalExceptionForError(env, clazz, err);
            }
        }
    }
    

    native层Parcel对象,writeInt32会调用writeAligned方法。

    status_t Parcel::writeAligned(T val) {
        COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(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;
    }
    

    mData代表写入的初始地址值,字节类型指针。mDataPos为当前指向的地址值偏移量。val计算出占用几个字节。当mDataPos偏移量加上val字节数不大于mDataCapacity容量时,mDataPos偏移再加上mData,为放置val的地址,通过*取指向的内容,设置为val,最后finishWrite更新mDataPos自增val的字节大小。
    若大于mDataCapacity,则growData扩容后restart_write重新设置。

    综上,Parcel写入的数据存储在native内存空间。

    回收Parcel

    Parcel#recycle()

    public final void recycle() {
        freeBuffer();
        final Parcel[] pool;
        if (mOwnsNativeParcelObject) {//构造方法自己创建的底层,mNativePtr值不变。
            pool = sOwnedPool;//存入sOwnedPool数组池
        } else {
            mNativePtr = 0;//本来就是传入的底层指针,设为0。
            pool = sHolderPool;
        }
    
        synchronized (pool) {
            for (int i=0; i<POOL_SIZE; i++) {
                if (pool[i] == null) {
                    pool[i] = this;
                    return;
                }
            }
        }
    }
    

    从0遍历每个数组元素,如果为空,则将数组该项设置调用者Parcel。
    若是自己创建的底层,则freeBuffer释放。
    JNI#nativeFreeBuffer方法

    static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            parcel->freeData();
        }
    }
    

    native层Parcel对象freeData方法。


    任重而道远

    相关文章

      网友评论

          本文标题:Parcel

          本文链接:https://www.haomeiwen.com/subject/xwjudftx.html