美文网首页
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