Serializable和Parcelable

Parcelable vs Serializable 性能對比
Android Parcel對象詳解
Parcelable最強解析

[toc]

當我們使用Intent傳遞一個對象的時候,需要實現序列化接口或者實現Parcelable接口。
用法很容易找到資料,這里不再贅述,推薦看這篇文章:序列化Serializable和Parcelable的理解和區別

下面主要分析下這兩者間的原理和性能對比。

1. Serializable原理

來看一個很簡單的類(直接從其它文章中復制過來的):

class TestSerial implements Serializable {
    public byte version = 100;
}

序列化之后是一個字節序列。轉化成十六進制解釋的話如下:

AC ED (序列化協議)
00 05 (序列化版本)
73     (TC_OBJECT. 新的對象)
72     (TC_CLASSDESC. 這是一個新類描述) 
00 0A  (類名的長度)
53 65 72 69 61 6C 54 65 73 74 (類的名稱) 
05 52 81 5A AC 66 02 F6 (SerialVersionUID)
02     (Various flags,0x02代表這個對象支持序列化) 
00 01  (類有幾個字段) 
49     (代表是int類型)
00 07  (字段名稱的長度)
76 65 72 73 69 6F 6E (version, 字段的名稱)
78     (TC_ENDBLOCKDATA, 描述的結束符)
70     (TC_NULL)
00 00 00 64 (version的值)

將一個對象序列化的時候,會首先寫入一些額外的信息,例如序列化協議、版本。然后是關于該對象的一些描述,例如類名和它的長度。最后才是對象中屬性。然而version = 100這個簡單的屬性用了非常復雜的方式保存,包含字段名、字段名長度、字段類型、字段值,所有的這些都是通過反射的方式獲取的。
想象一下如過類中有一個方法,那這個方法的序列化估計也是很復雜的,例如方法的返回值類型,入參類型,入參個數等。
所以序列化一個對象的開銷還是比較大的。更何況還有相同復雜程度的反序列化過程。然而這個過程又是必須的,因為序列化后的對象可能會交給另一個程序使用,這個對象的信息需要完整的保存下來。

2. Parcelable原理

對比序列化,Parcelable(這個不叫序列化,有人老喜歡將這個稱為序列化,不懂英文嗎)則輕量級很多,因為它們的實現目的不一樣。
序列化是為了持久化一個對象,可以保存在本地,也可以網絡傳輸,需要保證這個對象的完整性。而Parcelable的目的只是打包一組數據在Android應用組建之間傳輸,所以只需要在內存中保存即可,所以它不需要用到反射獲取屬性字段,也不需要保存額外的header信息,更不需要保存方法字段。

來看看一個簡單的實現了Parcelable接口的對象:

public class Test implements Parcelable {

    int i = 10;
    double d = 1.23456d;

    public static final Creator<Test> CREATOR = new Creator<Test>() {
        @Override
        public Test createFromParcel(Parcel in) {
            return new Test(in);
        }

        @Override
        public Test[] newArray(int size) {
            return new Test[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    protected Test(Parcel in) {
        i = in.readInt();
        d = in.readDouble();
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(i);
        dest.writeDouble(d);
    }
}

很明顯可以看到CREATOR是通過Test(Parcel in)這個構造來恢復一個對象的,而Parcel保存著這個對象的一些信息。這些信息由writeToParcel方法寫入到Parcel中,傳輸后再由Test(Parcel in)恢復。
由此可以看出Parcelable和Serilizable很大的區別,Parcelable只是將對象中的數據打包起來存入內存,不需要記錄它字段名類名等,對比序列化真的是簡單太多了。

Parcel是通過調用c/c++將數據直接存到內存中,具體實現這里就不分析了,看參考文章中有大致解釋。這里簡單做簡單說明:
Parcel是通過一段內存空間來保存數據的,當writeInt(i)調用時,往內存中寫入一段32位的數據,而當writeDouble(d)調用時,在后面又追加一段長度為64位的數據。而讀取的時候,也是按順序讀取,readInt()會讀取前32位的數據,轉換成int類型,讀取接著的64位,轉換成double。這就是為什么Parcelable的write方法和read方法順序要一致的原因。當然,實際存儲情況會更復雜,這里就不探究了,有興趣的自行查資料。

3. 總結

Serializable會序列化對象到一個字節序列中,這個字節序列保存了一些必要的header信息,還保存了類的描述,類的方法,對象的數據等,而這些信息都是通過反射的方式獲取的,不僅更消耗內存,還更加消耗性能。
而Parcelable則是打包對象中的一些數據,將它們的值按順序拼接起來,保存到內存中,讀取的時候也按順序讀取它們的長度。無需保存字段名,類名等額外信息,也用不上反射。所以Parcel對比序列化是更節省內存和更加高效的。

有人(看頂部引用的文章)對比過兩者的性能差距有十倍左右,但也只是毫秒級別的,所以如果是簡單的對象,使用Parcelable或Serialable,從人類的角度來看是沒有區別的。
所以,選擇Parcelable或是Serializable應該由程序員自己判定,前者更節省內存,更高效,但是使用起來麻煩,增加維護成本。而后者使用非常簡單,但是更耗費內存和性能。

另外再說下,切勿使用Serializable或者Parcelable在組建中傳遞高內存消耗的對象,例如大圖Bitmap,可能會導致內存溢出。
例如ActivityA中有一張圖片,序列化或者打包(Parcel)時,內存中又會保存這個圖片,而到達ActivityB時,又會重新實例化著圖片,一共使用類三份內存。而直接將圖片保存到本地,在ActivityB中重新加載,只消耗了兩份內存。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容