当前位置:主页 > 查看内容

Android Parcelable序列化源码解析

发布时间:2021-06-29 00:00| 位朋友查看

简介:序列化使用的帖子 Java Serializable、Android Parcelable序列化学习记录 Serializable序列化源码解析的帖子 Java Serializable序列化源码解析ObjectOutputStream、ObjectInputStream ヾ(?°?°?)欢迎大家去康康 本篇从使用Android Parcelable序列化一个简单……

序列化使用的帖子:Java Serializable、Android Parcelable序列化学习记录
Serializable序列化源码解析的帖子:Java Serializable序列化源码解析(ObjectOutputStream、ObjectInputStream)
ヾ(?°?°?)ノ゙欢迎大家去康康


本篇从使用Android Parcelable序列化一个简单的对象,对其序列化后的十六进制数据进行分析,然后对序列化过程的源码进行解读。
ヾ(?°?°?)ノ゙

序列化数据分析

先康康测试代码,将对象A序列化到文件p_test.txt中

public class PTest {
    static class A implements Parcelable {
        private String name;

        public A(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "A{" +
                    "name='" + name + '\'' +
                    '}';
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(this.name);
        }

        public void readFromParcel(Parcel source) {
            this.name = source.readString();
        }

        public A() {
        }

        protected A(Parcel in) {
            this.name = in.readString();
        }

        public static final Parcelable.Creator<A> CREATOR = new Parcelable.Creator<A>() {
            @Override
            public A createFromParcel(Parcel source) {
                return new A(source);
            }

            @Override
            public A[] newArray(int size) {
                return new A[size];
            }
        };
    }

    public static void write(){
        try {
            File file = new File("sdcard/p_test.txt");
            if(!file.exists()){
                file.createNewFile();
            }

            FileOutputStream fos = new FileOutputStream(file);
            Parcel parcel = Parcel.obtain();

            parcel.writeValue(new A("llk"));

            fos.write(parcel.marshall());

            parcel.setDataPosition(0);
            parcel.recycle();

            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void read(Context context){

        try {
            File file = new File("sdcard/p_test.txt");
            if(!file.exists()){
                Log.e("llk", "no file");
                return;
            }

            FileInputStream fis = new FileInputStream(file);
            Parcel parcel = Parcel.obtain();

            byte[] bytes = new byte[fis.available()];
            fis.read(bytes);

            parcel.unmarshall(bytes, 0, bytes.length);
            parcel.setDataPosition(0);

            Object obj = parcel.readValue(context.getClassLoader());
            Log.e("llk", "read a=" + obj);

            parcel.recycle();

            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


再打开p_text.txt之后,看看序列化后的数据。

//跟serialiable序列化后的数据一样,这是什么鬼,看不懂。
0400 0000 1400 0000 6300 6f00 6d00 2e00
6c00 6c00 6b00 2e00 6b00 7400 2e00 7300
2e00 5000 5400 6500 7300 7400 2400 4100
0000 0000 0300 0000 6c00 6c00 6b00 0000

//让我来翻译一下,现在是不是好看很多了。
类型		   长度   	  c    o    m    .
0400 0000 1400 0000 6300 6f00 6d00 2e00
l    l    k    .    k    t    .    s
6c00 6c00 6b00 2e00 6b00 7400 2e00 7300
.    P    T    e    s    t    $    A
2e00 5000 5400 6500 7300 7400 2400 4100
		      长度		   l    l    k
0000 0000 0300 0000 6c00 6c00 6b00 0000
  
0400 0000:类型标识,代表序列化的类是什么类型
1400 0000:代表长度(转为十进制后是20),表示后面是从 6300 - 4100 是一个整体
0300 0000:也是代表长度

源码相关类整理

Java

android.os.Parcel //java层Parcel类
android.os.Parcelable //序列化接口
android.os.Parcelable.Creator<T> //反序列化用到的创建类接口

C++

android-8.0/frameworks/base/core/jni/android_os_Parcel.cpp //java层定义的native方法进行关联
android-8.0/frameworks/native/libs/binder/Parcel.cpp //native层序列化Parcel类

序列化源码解析

Parcel parcel = Parcel.obtain();
parcel.writeValue(new A("llk"));
byte[] bytes = parcel.marshall();
parcel.recycle(); //释放Parcel对象

Java层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) {
                    pool[i] = null;
                    
                    ...
                      
                    //将读写工具类对象赋值给这个空Parcel对象
                    p.mReadWriteHelper = ReadWriteHelper.DEFAULT; 
                    return p;
                }
            }
        }
        return new Parcel(0);
    }

	//Parcel构造方法
	private Parcel(long nativePtr) {
    	...
    	init(nativePtr);
    }

    private void init(long nativePtr) {
      	//是否已经创建了native Parcel对象,如果没有就执行创建
      	//并缓存该native Parcel对象的指针地址,序列化都是通过这个native Parcel对象进行的
        if (nativePtr != 0) {
            mNativePtr = nativePtr;
            mOwnsNativeParcelObject = false;
        } else {
            mNativePtr = nativeCreate(); //nativeCreate是native方法了
            mOwnsNativeParcelObject = true;
        }
    }

obtain方法使用了享元模式,用于复用Parcel对象。在频繁使用到某个对象的场景,就可以享元模式来避免对象的频繁创建与销毁。(Handler Message#obtain()中也是类似用法)


Native层Parcel对象的创建过程

//android_os_Parcel.cpp
{"nativeCreate",              "()J", (void*)android_os_Parcel_create},

//android_os_Parcel.cpp#android_os_Parcel_create
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
  	//创建Parcel对象指针,并返回指针地址
    Parcel* parcel = new Parcel();
  	//强转成jlong后返回
    return reinterpret_cast<jlong>(parcel);
}

//Parcel.cpp#构造函数
Parcel::Parcel()
{
    LOG_ALLOC("Parcel %p: constructing", this);
    initState();
}

//Parcel.cpp#initState
void Parcel::initState()
{ //对一些变量进行初始化
    LOG_ALLOC("Parcel %p: initState", this);
    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);
  	//存储的为flat_binder_object结构
		//指向flat_binder_object数据地址,mObjects为__u32类型,即4字节的unsigned int,存的为各object写入时的mDataPos,
		//具体可以看writeObject方法
    mObjects = NULL;
    mObjectsSize = 0; //flat_binder_object数目
    mObjectsCapacity = 0; //可存储flat_binder_object容量
    mNextObjectHint = 0;
    mHasFds = false;
    mFdsKnown = true;
    mAllowFds = true;
    mOwner = NULL;
    mOpenAshmemSize = 0;
		...
}

native Parcel创建只是对一些数据进行初始化,最关键的就是把对象指针地址返回到java层了。

后续操作都是通过java层传入指针地址,获取到native Parcel对象进行操作的。


Parcel写入对象解析

类型标识符以及类名称的写入
		//Parcel#writeValue
		public final void writeValue(@Nullable Object v) {
	  			//一大波类型判断
	        if (v == null) {
	            writeInt(VAL_NULL);
	        } else if (v instanceof String) {
	            writeInt(VAL_STRING);
	            writeString((String) v);
	        } else if (v instanceof Integer) {
	            writeInt(VAL_INTEGER);
	            writeInt((Integer) v);
	        } else if (v instanceof Map) {
	            writeInt(VAL_MAP);
	            writeMap((Map) v);
	        } else if (v instanceof Bundle) {
	            // Must be before Parcelable
	            writeInt(VAL_BUNDLE);
	            writeBundle((Bundle) v);
	        } else if (v instanceof PersistableBundle) {
	            writeInt(VAL_PERSISTABLEBUNDLE);
	            writePersistableBundle((PersistableBundle) v);
	        } else if (v instanceof Parcelable) { //我们实现Parcelable,进来这里
	          	//序列化类型的写入,这里就是0400 0000的写入
	            writeInt(VAL_PARCELABLE); //private static final int VAL_PARCELABLE = 4;
	            writeParcelable((Parcelable) v, 0);
	        } else if (v instanceof Short) {
	            writeInt(VAL_SHORT);
	            writeInt(((Short) v).intValue());
	        } else if (v instanceof Long) {
	            writeInt(VAL_LONG);
	            writeLong((Long) v);
	        } else if (v instanceof Float) {
	            writeInt(VAL_FLOAT);
	            writeFloat((Float) v);
	        } else if (v instanceof Double) {
	            writeInt(VAL_DOUBLE);
	            writeDouble((Double) v);
	        } else if (v instanceof Boolean) {
	            writeInt(VAL_BOOLEAN);
	            writeInt((Boolean) v ? 1 : 0);
	        } else if (v instanceof CharSequence) {
	            // Must be after String
	            writeInt(VAL_CHARSEQUENCE);
	            writeCharSequence((CharSequence) v);
	        } else if (v instanceof List) {
	            writeInt(VAL_LIST);
	            writeList((List) v);
	        } else if (v instanceof SparseArray) {
	            writeInt(VAL_SPARSEARRAY);
	            writeSparseArray((SparseArray) v);
	        } else if (v instanceof boolean[]) {
	            writeInt(VAL_BOOLEANARRAY);
	            writeBooleanArray((boolean[]) v);
	        } else if (v instanceof byte[]) {
	            writeInt(VAL_BYTEARRAY);
	            writeByteArray((byte[]) v);
	        } else if (v instanceof String[]) {
	            writeInt(VAL_STRINGARRAY);
	            writeStringArray((String[]) v);
	        } else if (v instanceof CharSequence[]) {
	            writeInt(VAL_CHARSEQUENCEARRAY);
	            writeCharSequenceArray((CharSequence[]) v);
	        } else if (v instanceof IBinder) {
	            writeInt(VAL_IBINDER);
	            writeStrongBinder((IBinder) v);
	        } else if (v instanceof Parcelable[]) {
	            writeInt(VAL_PARCELABLEARRAY);
	            writeParcelableArray((Parcelable[]) v, 0);
	        } else if (v instanceof int[]) {
	            writeInt(VAL_INTARRAY);
	            writeIntArray((int[]) v);
	        } else if (v instanceof long[]) {
	            writeInt(VAL_LONGARRAY);
	            writeLongArray((long[]) v);
	        } else if (v instanceof Byte) {
	            writeInt(VAL_BYTE);
	            writeInt((Byte) v);
	        } else if (v instanceof Size) {
	            writeInt(VAL_SIZE);
	            writeSize((Size) v);
	        } else if (v instanceof SizeF) {
	            writeInt(VAL_SIZEF);
	            writeSizeF((SizeF) v);
	        } else if (v instanceof double[]) {
	            writeInt(VAL_DOUBLEARRAY);
	            writeDoubleArray((double[]) v);
	        } else {
	            Class<?> clazz = v.getClass();
	            if (clazz.isArray() && clazz.getComponentType() == Object.class) {
	                writeInt(VAL_OBJECTARRAY);
	                writeArray((Object[]) v);
	            } else if (v instanceof Serializable) { //居然还有Serializable的
	                // Must be last
	                writeInt(VAL_SERIALIZABLE);
	                writeSerializable((Serializable) v);
	            } else {
	                throw new RuntimeException("Parcel: unable to marshal value " + v);
	            }
	        }
	    }
	
			//Parcel#writeSerializable
			//八卦一下writeSerializable做了什么
			//暴风哭泣,Serializable还是用回Serializable的序列化方式
			public final void writeSerializable(@Nullable Serializable s) {
	        ...
	        String name = s.getClass().getName();
	        writeString(name);
	
	        ByteArrayOutputStream baos = new ByteArrayOutputStream();
	        try {
	            ObjectOutputStream oos = new ObjectOutputStream(baos);
	            oos.writeObject(s);
	            oos.close();
	            writeByteArray(baos.toByteArray());
	        } catch (IOException ioe) {
	            ...
	        }
	    }

		//Parcel#writeParcelable
		public final void writeParcelable(@Nullable Parcelable p, int parcelableFlags) {
	        ...
	        
	       	//写入类的详细名称
	        writeParcelableCreator(p);
	      	//???直接调用了我们实现的Parcelable#writeToParcel方法。。。
	      	//也就是说,我们想给类写入什么就写入什么,序列化器不关心。全部交由我们处理
	        p.writeToParcel(this, parcelableFlags);
    	}

		//Parcel#writeParcelableCreator
		public final void writeParcelableCreator(@NonNull Parcelable p) {
	      	//这里会写入 类名长度 + 类名
	        String name = p.getClass().getName();
	        writeString(name);
    	}

从上面看出,序列化器把需要序列化的内容丢回给我们自己去决定。我们想给类写入什么就写入什么,序列化器不关心。


变量值的写入
		//PTest.A#writeToParcel	
		public void writeToParcel(Parcel dest, int flags) {
			dest.writeString(this.name);
		}

		//Parcel#writeString
		public final void writeString(@Nullable String val) {
        	mReadWriteHelper.writeString(this, val);
    	}

		//ReadWriteHelper#writeString
		public void writeString(Parcel p, String s) {
      		//这里是native方法了,传入native Parcel指针地址以及需要序列化的内容
    		nativeWriteString(p.mNativePtr, s);
    	}

		//android_os_Parcel.cpp#android_os_Parcel_writeString
		{"nativeWriteString",         "(JLjava/lang/String;)V",(void*)android_os_Parcel_writeString},
	
		static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
	    {
	        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr); //通过地址强转成Parcel对象指针
	        if (parcel != NULL) {
	            status_t err = NO_MEMORY;
	            if (val) {
	                //申请这个java string对象的使用权,防止val对象刚好正在GC导致本地代码一直阻塞的问题
	                //后续会详细说明Get/ReleaseStringCritical
	                const jchar* str = env->GetStringCritical(val, 0);
	                if (str) {
	                    //执行写入内容、以及内容的长度
	                    err = parcel->writeString16(
	                        reinterpret_cast<const char16_t*>(str),
	                        env->GetStringLength(val));
	                    env->ReleaseStringCritical(val, str); //释放这个java string对象使用权
	                }
	            } else {
	                err = parcel->writeString16(NULL, 0);
	            }
	            if (err != NO_ERROR) {
	                signalExceptionForError(env, clazz, err);
	            }
	        }
	    }

从上面看出,写入逻辑主要是依靠native Parcel对象完成。那我们继续分析一些native Parcel中的这些写函数。


Get/ReleaseStringCritical
大佬文章:https://www.jianshu.com/p/e4dd44871d3d

在Java中创建的对象全都由GC(垃圾回收器)自动回收,不需要像C/C++一样需要程序员自己管理内存。GC会实时扫描所有创建的对象是否还有引用,如果没有引用则会立即清理掉。当我们创建一个像int数组对象的时候,当我们在本地代码想去访问时,发现这个对象正被GC线程占用了,这时本地代码会一直处于阻塞状态,直到等待GC释放这个对象的锁之后才能继续访问。为了避免这种现象的发生,JNI提供了Get/ReleasePrimitiveArrayCritical这对函数,本地代码在访问数组对象时会暂停GC线程。不过使用这对函数也有个限制,在Get/ReleasePrimitiveArrayCritical这两个函数期间不能调用任何会让线程阻塞或等待JVM中其它线程的本地函数或JNI函数,和处理字符串的Get/ReleaseStringCritical函数限制一样。这对函数和GetIntArrayElements函数一样,返回的是数组元素的指针。
这是一对函数,有很多。格式为:Get/ReleaseXXXCritical


native Parcel#writeString16函数解析
		//Parcel.cpp#writeString16
		status_t Parcel::writeString16(const char16_t* str, size_t len)
	    {
	        if (str == NULL) return writeInt32(-1);
	
	      	//先写入长度,如果没出错才写入内容
	        status_t err = writeInt32(len);
	        if (err == NO_ERROR) {
	          	//sizeof(char16_t) = 2
	          	//以llk这个字符串为例子的话,len *= sizeof(char16_t) = 6
	            len *= sizeof(char16_t);
	          	//len+sizeof(char16_t) = 8
	          	//writeInplace函数返回要写入的地址
	            uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
	            if (data) {
	              	//memcpy函数是c++的内存拷贝函数,通过memcpy将内容拷贝到data内存中。
	                memcpy(data, str, len);
	                ...
	                return NO_ERROR;
	            }
	            err = mError;
	        }
	        return err;
	    }

		//这个宏定义是为了保证s是4的倍数
		//先+3是为了保证s大于等于4
		//然后再&~3为了保证最低两位为00(~3=00,s&00必定是...00),这样就能保证s是4的倍数
		#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3)
		
	    //Parcel.cpp#pad_size 是PAD_SIZE_UNSAFE宏定义的封装
	    static size_t pad_size(size_t s) {
	        ...
	        return PAD_SIZE_UNSAFE(s);
	    }

		//Parcel.cpp#writeInplace
    	void* Parcel::writeInplace(size_t len)
	    {
	        ...
	
	        //保证写入的内容是4的倍数
	        //也就是说上边序列化数据分析中看到的
	        //以com.llk.kt.s.PTest$A为例,传入的len = 20(字符串长度) * 2 + 2 = 42,最终pad_size后得到44
	       	//再以llk为例,传入的len = 3(字符串长度) * 2 + 2 = 8,最终pad_size后得到8
	        const size_t padded = pad_size(len);
	
	        ...
	
	        //判断当前内存总大小是否住够写入,如果不够先执行扩容再goto回来
	        if ((mDataPos+padded) <= mDataCapacity) {
	    restart_write:
	            uint8_t* const data = mData+mDataPos; //计算写入位置,并返回
	
	            //说实话,下面这段我看不懂。溜了溜了
	          	//猜测这里的逻辑是补位,空位不上0000之类的
	          	//因为序列化数据看到写入类名的时候,6300 - 4100后还有0000 0000估计是这里补的吧
	            if (padded != len) {
	    #if BYTE_ORDER == BIG_ENDIAN
	                static const uint32_t mask[4] = {
	                    0x00000000, 0xffffff00, 0xffff0000, 0xff000000
	                };
	    #endif
	    #if BYTE_ORDER == LITTLE_ENDIAN
	                static const uint32_t mask[4] = {
	                    0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff
	                };
	    #endif
	                *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];
	            }
	
	            finishWrite(padded);
	            return data;
	        }
	
	        status_t err = growData(padded); //执行扩容
	        if (err == NO_ERROR) goto restart_write; //回到restart_write位置再执行
	        return NULL;
	    }

		//Parcel.cpp#growData 申请一块比现在大1.5倍的内存
	    status_t Parcel::growData(size_t len)
	    {
	        size_t newSize = ((mDataSize+len)*3)/2;
	        return (newSize <= mDataSize)
	                ? (status_t) NO_MEMORY
	                : continueWrite(newSize);
	    }
	
		//Parcel#finishWrite 给指针位置移位
	    status_t Parcel::finishWrite(size_t len)
	    {
	        ...
	
	        mDataPos += len;
	        if (mDataPos > mDataSize) {
	            mDataSize = mDataPos;
	        }
	        return NO_ERROR;
	    }

native Parcel#writeInt32函数解析
		//Parcel.cpp#writeInt32
		status_t Parcel::writeInt32(int32_t val)
	    {
	        return writeAligned(val);
	    }


		//Parcel.cpp#writeAligned
    	template<class T>
	    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:
	          	//这里写入val值
	            *reinterpret_cast<T*>(mData+mDataPos) = val;
	            return finishWrite(sizeof(val));
	        }
	
	      	//如果内存不够,会进去扩容然后goto回到restart_write再执行
	        status_t err = growData(sizeof(val));
	        if (err == NO_ERROR) goto restart_write;
	        return err;
	    }

marshall方法

		public final byte[] marshall() {
        	return nativeMarshall(mNativePtr);
    	}

		{"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},

		static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
	    {
	        //指针地址强转成Parcel对象指针
	        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
	        if (parcel == NULL) {
	           return NULL;
	        }
	
	        //如果parcel中有binder对象,就不能调用marshall
	        if (parcel->objectsCount())
	        {
	            jniThrowException(env, "java/lang/RuntimeException", "Tried to marshall a Parcel that contained Binder objects.");
	            return NULL;
	        }
	
	        //根据序列化的数据大小,创建一个java字节数组
	        jbyteArray ret = env->NewByteArray(parcel->dataSize());
	
	        if (ret != NULL)
	        {		
	          	//申请这个java字节数组对象的使用权
	            jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(ret, 0);
	            if (array != NULL)
	            {
	                //将序列化的数据拷贝到这个java字节数组
	                memcpy(array, parcel->data(), parcel->dataSize());
	                env->ReleasePrimitiveArrayCritical(ret, array, 0); //释放这个java字节数组对象的使用权
	            }
	        }
	
	        return ret; //返回这个带有序列化数据的java字节数组
	    }

marshall方法就是将序列化数据拷贝给一个java字节数组并返回到java层。然后你就可以为所欲为了,比如我最上边的例子是将它保存到文件。


小结

可以看出,Parcel的序列化是直接写入到内存的。而且也并没有过多的包装数据,就写入了类型标识、类名、变量值等。

而且真正执行变量值写入是根据我们实现的writeToParcel方法来进行的。所有我们可以通过writeToParcel来处理那些数据需要写入,哪些不需要写入。


反序列化源码解析

parcel.unmarshall(bytes, 0, bytes.length);
parcel.setDataPosition(0);
Object obj = parcel.readValue(context.getClassLoader());

unmarshall方法解析

		//Parcel#unmarshall
		public final void unmarshall(@NonNull byte[] data, int offset, int length) {
        	updateNativeSize(nativeUnmarshall(mNativePtr, data, offset, length));
    	}

		{"nativeUnmarshall",          "(J[BII)J", (void*)android_os_Parcel_unmarshall},

    	//android_os_Parcel.cpp#android_os_Parcel_unmarshall
    	static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
                                              jbyteArray data, jint offset, jint length)
	    {
	        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
	        if (parcel == NULL || length < 0) {
	           return 0;
	        }
	
	        //申请jbyteArray data的使用权
	        jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
	        if (array)
	        {
	            parcel->setDataSize(length); //设置内存长度
	            parcel->setDataPosition(0); //重置指针位置
	
	            void* raw = parcel->writeInplace(length);
	            memcpy(raw, (array + offset), length); //将数据拷贝到native层的parcel
	
	            //释放jbyteArray data的使用权
	            env->ReleasePrimitiveArrayCritical(data, array, 0);
	        }
	        return parcel->getOpenAshmemSize();
	    }

unmarshall方法主要是进行了将序列化数据拷贝到native层的parcel。


为啥要在unmarshall后再setDataPosition(0)

    public final void setDataPosition(int pos) {
        nativeSetDataPosition(mNativePtr, pos);
    }

	{"nativeSetDataPosition",     "(JI)V", (void*)android_os_Parcel_setDataPosition},

	//android_os_Parcel.cpp#android_os_Parcel_setDataPosition
	static void android_os_Parcel_setDataPosition(jlong nativePtr, jint pos)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            parcel->setDataPosition(pos);
        }
    }

	//Parcel.cpp#setDataPosition
	void Parcel::setDataPosition(size_t pos) const
    {
        ...
        mDataPos = pos;
        ...
    }

setDataPosition方法很简答,就是对native层Parcel对象的指针位置进行设置而已。

那为什么要在unmarshall之后再设置一次mDataPos呢?在native层Parcel对象的unmarshall函数里边不是已经设置过mDataPos = 0了吗?

	//原因是在parcel->writeInplace(length);的时候,mDataPos指针位置又进行了偏移
	//writeInplace函数里边最后再返回之前调用了finishWrite函数
  
  	status_t Parcel::finishWrite(size_t len)
    {
        ...

        mDataPos += len; //在这里指针位置偏移了
        if (mDataPos > mDataSize) {
            mDataSize = mDataPos;
        }
        return NO_ERROR;
    }

如果没有及时重置mDataPos位置的话就会读不到数据。


readValue方法解析

	//Parcel#readValue
	public final Object readValue(@Nullable ClassLoader loader) {
        int type = readInt(); //读取类型标识

        switch (type) {
        case VAL_NULL:
            return null;
        case VAL_STRING:
            return readString();
        case VAL_INTEGER:
            return readInt();
        case VAL_MAP:
            return readHashMap(loader);
        case VAL_PARCELABLE: //走这里咯
            return readParcelable(loader);
        case VAL_SHORT:
            return (short) readInt();
        case VAL_LONG:
            return readLong();
        case VAL_FLOAT:
            return readFloat();
        case VAL_DOUBLE:
            return readDouble();
        case VAL_BOOLEAN:
            return readInt() == 1;
        case VAL_CHARSEQUENCE:
            return readCharSequence();
        case VAL_LIST:
            return readArrayList(loader);
        case VAL_BOOLEANARRAY:
            return createBooleanArray();
        case VAL_BYTEARRAY:
            return createByteArray();
        case VAL_STRINGARRAY:
            return readStringArray();
        case VAL_CHARSEQUENCEARRAY:
            return readCharSequenceArray();
        case VAL_IBINDER:
            return readStrongBinder();
        case VAL_OBJECTARRAY:
            return readArray(loader);
        case VAL_INTARRAY:
            return createIntArray();
        case VAL_LONGARRAY:
            return createLongArray();
        case VAL_BYTE:
            return readByte();
        case VAL_SERIALIZABLE:
            return readSerializable(loader);
        case VAL_PARCELABLEARRAY:
            return readParcelableArray(loader);
        case VAL_SPARSEARRAY:
            return readSparseArray(loader);
        case VAL_SPARSEBOOLEANARRAY:
            return readSparseBooleanArray();
        case VAL_BUNDLE:
            return readBundle(loader);
        case VAL_PERSISTABLEBUNDLE:
            return readPersistableBundle(loader);
        case VAL_SIZE:
            return readSize();
        case VAL_SIZEF:
            return readSizeF();
        case VAL_DOUBLEARRAY:
            return createDoubleArray();
        default:
            int off = dataPosition() - 4;
            throw new RuntimeException(
                "Parcel " + this + ": Unmarshalling unknown type code " + type + " at offset " + off);
        }
   }

	//Parcel#readParcelable
	public final <T extends Parcelable> T readParcelable(@Nullable ClassLoader loader) {
      	//获取类对象里边的Parcelable.Creator
        Parcelable.Creator<?> creator = readParcelableCreator(loader);
        if (creator == null) {
            return null;
        }
        ...
        //直接调用createFromParcel方法
        return (T) creator.createFromParcel(this);
   }

	//Parcel#readParcelableCreator 主要逻辑就是,反序列化类名,然后反射获取其CREATOR属性,最后返回
	public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
        String name = readString(); //反序列化类名
        if (name == null) {
            return null;
        }
        Parcelable.Creator<?> creator;
        synchronized (mCreators) {
            //从缓存里边去
            HashMap<String,Parcelable.Creator<?>> map = mCreators.get(loader);
            if (map == null) {
                map = new HashMap<>();
                mCreators.put(loader, map);
            }
            creator = map.get(name);
            //如果缓存没有就通过类名反射,获取到Class对象
            //然后再反射获取其内部的属性CREATOR
            if (creator == null) {
                try {
                    ClassLoader parcelableClassLoader =
                            (loader == null ? getClass().getClassLoader() : loader);
                    Class<?> parcelableClass = Class.forName(name, false /* initialize */,
                            parcelableClassLoader);
                    if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
                        throw new BadParcelableException("Parcelable protocol requires subclassing "
                                + "from Parcelable on class " + name);
                    }
                    Field f = parcelableClass.getField("CREATOR");
                    if ((f.getModifiers() & Modifier.STATIC) == 0) {
                        throw new BadParcelableException("Parcelable protocol requires "
                                + "the CREATOR object to be static on class " + name);
                    }
                    Class<?> creatorType = f.getType();
                    if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
                        throw new BadParcelableException("Parcelable protocol requires a "
                                + "Parcelable.Creator object called "
                                + "CREATOR on class " + name);
                    }
                    creator = (Parcelable.Creator<?>) f.get(null);
                }
                catch (IllegalAccessException e)
                ...
                //添加到缓存
                map.put(name, creator);
            }
        }

       return creator;
   }

最终读取逻辑,还是回到我们代码实现的Parcelable.Creator里边去。序列化流程是依靠writeToParcel方法里边的调用顺序来进行的写入的话,那么反序列化流程也必须准遵循这个顺序进行读取,不然就会读取数据出错。


		//PTest#A
		protected A(Parcel in) {
            this.name = in.readString();
        }

        public static final Parcelable.Creator<A> CREATOR = new Parcelable.Creator<A>() {
            @Override
            public A createFromParcel(Parcel source) {
                return new A(source);
            }

            @Override
            public A[] newArray(int size) {
                return new A[size];
            }
        };

readString、readInt的源码就不进行深入分析了。其读取流程也是通过native的parcel对象进行读取,序列化是怎么写入的,反序列化就是怎么读取。就不继续往下分析了。

溜了溜了。


小结

unmarshall方法后必须先重置下指针位置,才能够正常读取数据;

Parcelable方式的序列化唯一用到反射的地方,就是在反序列化中获取类中的 CREATOR属性;

序列化、反序列化过程中,读写变量值顺序必须保持一致,才能读取到正确值。


总结

通过解析Parcelable序列化过程可以看出,它序列化的数据非常简洁,而且序列化过程非常简单而直接。是一个轻度的序列化方案,适合用在对性能有一定要求的场景。所有Android才专门设计出Parcelable序列化,提供给进程间通讯使用的。

;原文链接:https://blog.csdn.net/yudan505/article/details/115680320
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!
上一篇:App多渠道签名打包 下一篇:没有了

推荐图文


随机推荐