序列化使用的帖子:Java Serializable、Android Parcelable序列化學習記錄
Serializable序列化原始碼決議的帖子:Java Serializable序列化原始碼決議(ObjectOutputStream、ObjectInputStream)
ヾ(?°?°?)ノ゙歡迎大家去康康
本篇從使用Android Parcelable序列化一個簡單的物件,對其序列化后的十六進制資料進行分析,然后對序列化程序的原始碼進行解讀,
ヾ(?°?°?)ノ゙
文章目錄
- 序列化資料分析
- 原始碼相關類整理
- 序列化原始碼決議
- Java層Parcel物件的創建程序
- Native層Parcel物件的創建程序
- Parcel寫入物件決議
- 型別識別符號以及類名稱的寫入
- 變數值的寫入
- native Parcel#writeString16函式決議
- native Parcel#writeInt32函式決議
- marshall方法
- 小結
- 反序列化原始碼決議
- unmarshall方法決議
- 為啥要在unmarshall后再setDataPosition(0)
- readValue方法決議
- 小結
- 總結
序列化資料分析
先康康測驗代碼,將物件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://www.uj5u.com/yidong/275822.html
標籤:其他
下一篇:App多渠道簽名打包
