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传输数组
网友评论