美文网首页
2020-03-24-Android的序列化

2020-03-24-Android的序列化

作者: 耿望 | 来源:发表于2020-03-29 16:35 被阅读0次

    Parcelable

    因为上层的代码比较简单,就是实现Parcelable接口,重写那几个方法,这里就不多写了。这里画了一张时序图,是Intent之间传递Parcel数据的过程,主要是序列化和反序列化。有一点需要注意的是变量的读写顺序必须保持一致,因为读写的时候是不会保留变量名的,不像Bundle,Bundle是一个map结构,会保存key-value键值对。


    Parcel (1).jpg

    实际上它的主要实现在native层,是一种共享内存的方式。


    Parcel.jpg

    以String为例,我们来看下读写的大概流程。
    我们看下Parcel类,大部分是native方法。

            public String readString(Parcel p) {
                return nativeReadString(p.mNativePtr);
            }
            public void writeString(Parcel p, String s) {
                nativeWriteString(p.mNativePtr, s);
            }
        static native String nativeReadString(long nativePtr);
        static native void nativeWriteString(long nativePtr, String val);
    

    主要实现在jni层,这里附上源码链接:
    frameworks/base/core/jni/android_os_Parcel.cpp

    static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            size_t len;
            const char16_t* str = parcel->readString16Inplace(&len);
            if (str) {
                return env->NewString(reinterpret_cast<const jchar*>(str), len);
            }
            return NULL;
        }
        return NULL;
    }
    static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            status_t err = NO_MEMORY;
            if (val) {
                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);
                }
            } else {
                err = parcel->writeString16(NULL, 0);
            }
            if (err != NO_ERROR) {
                signalExceptionForError(env, clazz, err);
            }
        }
    }
    

    这里又使用了另一个文件,Parcel.cpp,这里附上源码链接
    frameworks/native/libs/binder/Parcel.cpp

    const char16_t* Parcel::readString16Inplace(size_t* outLen) const
    {
        int32_t size = readInt32();
        // watch for potential int overflow from size+1
        if (size >= 0 && size < INT32_MAX) {
            *outLen = size;
            const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));
            if (str != nullptr) {
                return str;
            }
        }
        *outLen = 0;
        return nullptr;
    }
    status_t Parcel::writeString16(const char16_t* str, size_t len)
    {
        if (str == nullptr) return writeInt32(-1);
    
        status_t err = writeInt32(len);
        if (err == NO_ERROR) {
            len *= sizeof(char16_t);
            uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));
            if (data) {
                memcpy(data, str, len);//1
                *reinterpret_cast<char16_t*>(data+len) = 0;
                return NO_ERROR;
            }
            err = mError;
        }
        return err;
    }
    

    可以看到注释1处,使用了一个内存拷贝函数,memcpy方法,对这块内存进行了一个拷贝。

    参考:

    序列化原理(二):从源码理解Parcelable
    Android高级架构进阶之数据传输与序列化
    探索Android中的Parcel机制
    Android native进程间通信实例-binder篇之—用parcel传输数组

    相关文章

      网友评论

          本文标题:2020-03-24-Android的序列化

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