Android Serializable與Parcelable原理與區別

來源:互聯網
上載者:User

 

一、序列化、還原序列化是什嗎?(1) 名詞解釋對象的序列化 : 把Java對象轉換為位元組序列並儲存至一個儲存媒介的過程。
對象的還原序列化:把位元組序列恢複為Java對象的過程。
(2) 序列化詳細解釋對象的序列化涉及三個點關鍵點:Java對象、位元組序列、儲存。

1. Java對象的組成?
Java對象包含變數與方法。但是序列與還原序列化僅處理Java變數而不處理方法,序列與還原序列化僅對資料進行處理。

2. 什麼是字元序列?
字元序列是兩個詞,字元是在電腦和電信領域中,字元(Character)是一個資訊單位。數學上,序列是被排成一列的對象(或事件)。
《字元-維基百科》 , 《序列-維基百科》 說白了就是連續排列的多個字元的集合。類似於1A165613246546

3. 儲存
字元序列需要儲存到一個地方,可以是硬碟也可以是記憶體。
簡單說法是:序列化把當前對象資訊儲存下來。還原序列化剛好相反的操作。


二、Java對象與Java對象序列化的區別?Java對象存在的前提必須在JVM運行期間存在,如果想在JVM非啟動並執行情況下或者在其他機器JVM上擷取指定Java對象,在現有Java對象的機制下都不可能完成。
與Java對象不同的是,如果對Java對象執行序列化操作,因為原理是把Java對象資訊儲存到儲存媒介,所以可以在以上Java對象不可能存在的兩種情況下依然可以使用Java對象。


三、為什麼要使用序列化、還原序列化?根據以上對序列化、還原序列化的理解,這個疑問可以翻譯成,為什麼需要把對象資訊儲存到儲存媒介中並之後讀取出來?
因為二中的解釋,開發中有在JVM非啟動並執行情況下或者在其他機器JVM上擷取指定Java對象的需求。


四、Android 中Serializable與Parcelable區別?兩種都是用於支援序列化、還原序列化話操作,兩者最大的區別在於儲存媒介的不同,Serializable使用IO讀寫儲存在硬碟上,而Parcelable是直接在記憶體中讀寫,很明顯記憶體的讀寫速度通常大於IO讀寫,所以在Android中通常優先選擇Parcelable。
Serializable不是當前關注的焦點,不過可以查看《Java序列化演算法透析》這篇文章中實現一個簡單的Serializable例子,查看序列化產生的IO檔案,並且以16進位讀取並一一解釋每一個16進位數位含義。


五、Parcelable舉例在Android中實現Parcelable介面的類可以支援序列與還原序列化,以下是一個實現的舉例:
1. 實現Parcelable介面
2. 添加實體屬性
3. 覆寫writeToParcel(Parcel dest, int flags)方法,指定寫入Parcel類的資料。
4. 建立Parcelable.Creator靜態對象,有兩個方法createFromParcel(Parcel in)與newArray(int size),前者指定如何從Parcel中讀取出資料對象,後者建立一個數組。
5. 覆寫describeContents方法,預設返回0。
public class Gril implements Parcelable {     private int mAge; // 年齡     private boolean mSexy; // 是否性感         @Override     public void writeToParcel(Parcel dest, int flags) {          dest.writeInt(mAge);          dest.writeByte((byte) (mSexy ? 1 : 0));     }         public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {          public Gril createFromParcel(Parcel in) {               Gril gril = new Gril();               gril.mAge = in.readInt();               gril.mSexy = in.readByte() != 0;              return gril;          }                   public Gril[] newArray(int size) {              return new Gril[size];          }     };         @Override     public int describeContents() {          return 0;     }}


六、Parcelable原理

從上面的例子中可以看出,具體的寫入(dest.writeInt(mAge);)與讀取(gril.mAge = in.readInt();)都是針對Parcel對象進行的操作,下面貼出的是Parcle 讀寫int類型資料的定義。

 

public final class Parcel {    ......        /**     * Write an integer value into the parcel at the current dataPosition(),     * growing dataCapacity() if needed.     */    public final native void writeInt(int val);    /**     * Read an integer value from the parcel at the current dataPosition().     */    public final native int readInt();         ......}


 

從上面代碼可以看出都是native方法說明都是使用JNI,其具體位置在system/frameworks/base/core/jni/android_util_Binder.cpp ,以下也僅以int類型讀寫為例

static void android_os_Parcel_writeInt(JNIEnv* env, jobject clazz, jint val){    Parcel* parcel = parcelForJavaObject(env, clazz);    if (parcel != NULL) {        const status_t err = parcel->writeInt32(val);        if (err != NO_ERROR) {            jniThrowException(env, java/lang/OutOfMemoryError, NULL);        }    }}static jint android_os_Parcel_readInt(JNIEnv* env, jobject clazz){    Parcel* parcel = parcelForJavaObject(env, clazz);    if (parcel != NULL) {        return parcel->readInt32();    }    return 0;}


從上面可以看出都會調用Parcel實現且分別調用writeInt32與readInt32函數,接著來看看具體實現。位置:/system/frameworks/base/libs/binder/Parcel.cpp

status_t Parcel::writeInt32(int32_t val){    return writeAligned(val);}templatestatus_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(mData+mDataPos) = val;        return finishWrite(sizeof(val));    }    status_t err = growData(sizeof(val));    if (err == NO_ERROR) goto restart_write;    return err;}status_t Parcel::readInt32(int32_t *pArg) const{    return readAligned(pArg);}templatestatus_t Parcel::readAligned(T *pArg) const {    COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));    if ((mDataPos+sizeof(T)) <= mDataSize) {        const void* data = mData+mDataPos;        mDataPos += sizeof(T);        *pArg =  *reinterpret_cast(data);        return NO_ERROR;    } else {        return NOT_ENOUGH_DATA;    }}

以下4點摘自《探索Android中的Parcel機制(上)》
有興趣的朋友可以自己讀一下,不難理解,這裡把基本的思路總結一下:
1. 整個讀寫全是在記憶體中進行,主要是通過malloc()、realloc()、memcpy()等記憶體操作進行,所以效率比JAVA序列化中使用外部儲存空間會高很多;
2. 讀寫時是4位元組對齊的,可以看到#define PAD_SIZE(s) (((s)+3)&~3)這句宏定義就是在做這件事情;
3. 如果預分配的空間不夠時newSize = ((mDataSize+len)*3)/2;會一次多分配50%;

4. 對於普通資料,使用的是mData記憶體位址,對於IBinder類型的資料以及FileDescriptor使用的是mObjects記憶體位址。後者是通過flatten_binder()和unflatten_binder()實現的,目的是還原序列化時讀出的對象就是原對象而不用重新new一個新對象。

 

七、序列化還原序列化Parcelable實驗?1. 任何實體類都需要複寫Parcelable介面嗎?
2. 如果子類新增屬性,需要複寫父類writeToParcel與CREATOR嗎?
3. writeToParcel 與 createFromParcel 對變數的讀寫前後順序可以不一致嗎,會出現什麼結果?
4. 讀寫Parcelable對象(寫操作dest.writeParcelable(obj, flags); 讀操作in.readParcelable(ObjectA.class.getClassLoader()); )
5. 讀寫Parcelable對象數組
dest.writeParcelableArray(mClassNameList.toArray(new ClassName[mClassNameList.size()]), flags);Parcelable[] parcelableArr = in.readParcelableArray(ClassName.class.getClassLoader());ArrayList arrayList = new ArrayList();for (Parcelable object : parcelableArr) {     arrayList.add((ClassName)object);}


八、自己實現序列與還原序列化機制《C 語言的資料序列化 (C語言實現序列化機制的思路)》



 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.