Serialize是java原生就自带的东西,我们可以看到android的源码
所以看看android是如何实现parcel的,这对我们自己代码设计有什么启发。
Parcel:
在android中,parcel的源码如下:
Frameworks/base/core/java/android/os/Parcel.java
/** * Write an integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeInt(int val) { nativeWriteInt(mNativePtr, val); } /** * Write a long integer value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeLong(long val) { nativeWriteLong(mNativePtr, val); }
常见方法:
obtain() 获得一个新的parcel ,相当于new一个对象 dataSize() 得到当前parcel对象的实际存储空间 dataCapacity() 得到当前parcel对象的已分配的存储空间, >=dataSize()值 (以空间换时间) dataPostion() 获得当前parcel对象的偏移量(类似于文件流指针的偏移量) setDataPosition() 设置偏移量 recyle() 清空、回收parcel对象的内存 writeInt(int) 写入一个整数 writeFloat(float) 写入一个浮点数 writeDouble(double) 写入一个双精度数 writeString(string) 写入一个字符串 当然,还有更多的writeXXX()方法,与之对应的就是readXXX(),具体方法请参阅SDK。 其中几个值得注意的方法为: writeException() 在Parcel队头写入一个异常 writeException() Parcel队头写入“无异常“ readException() 在Parcel队头读取,若读取值为异常,则抛出该异常;否则,程序正常运行。
我们来分析下:
status_t Parcel::writeInt32(int32_t val) { return writeAligned(val); }
template<class T> status_t Parcel::writeAligned(T val) { COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(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; }
我们来分析writeAligned:
首先是
#define PAD_SIZE(s) (((s)+3)&~3)
&~3:
考虑16进制,~3 -> 0x11111100 在做&
也就是说前面6位不变,最后2位为0.
或者说,把最后2位变成0.也就是4的倍数。
+3的目的是,把当前的值向上取最近的整除4的值,如果本身就是那就不变。
所以就和宏的目的就是按4字节对齐!
所以writeAligned是写入4字节对齐的内容。
常见的是int32 和int64等。
status_t Parcel::growData(size_t len) { size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY : continueWrite(newSize); }
当内存不够的时候,会申请一块3/2块大小的内存,使得现在parcel可以使用。
所以parcel本质的是最内存的操作,而且操作位memcpy等。
查看continueWrite函数,由于很复杂,就不列出来了,
看看关键的地方:
size_t* objects = (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));
扩大内存,啊哈。就是这个地方了。
所以整个parcel的读写都在内存中操作的。