1. 程式人生 > >Android系統中Parcelable和Serializable的區別

Android系統中Parcelable和Serializable的區別

進行Android開發的時候,我們都知道不能將物件的引用傳給Activities或者Fragments,我們需要將這些物件放到一個Intent或者Bundle裡面,然後再傳遞。

通過Android的API,我們知道有兩種選擇,即在傳遞物件時,需要對我們的物件進行 Parcelable 或者Serializable化。作為Java開發者,相信大家對Serializable 機制有一定了解,那為什麼還需要 Parcelable呢?

為了回答這個問題,讓我們分別來看看這兩者的差異。

Serializable, 簡單易用

// access modifiers, accessors and constructors omitted for brevity
public class SerializableDeveloper implements Serializable String name; int yearsOfExperience; List<Skill> skillSet; float favoriteFloat; static class Skill implements Serializable { String name; boolean programmingRelated; } }

serializable的迷人之處在於你只需要對某個類以及它的屬性實現Serializable 介面即可。Serializable 介面是一種標識介面(

marker interface),這意味著無需實現方法,Java便會對這個物件進行高效的序列化操作。

這種方法的缺點是使用了反射,序列化的過程較慢。這種機制會在序列化的時候建立許多的臨時物件,容易觸發垃圾回收。

Parcelable, 速度至上

// access modifiers, accessors and regular constructors ommited for brevity
class ParcelableDeveloper implements Parcelable {
    String name;
    int yearsOfExperience;
    List<Skill> skillSet;
    float favoriteFloat;

    ParcelableDeveloper(Parcel in) {
        this
.name = in.readString(); this.yearsOfExperience = in.readInt(); this.skillSet = new ArrayList<Skill>(); in.readTypedList(skillSet, Skill.CREATOR); this.favoriteFloat = in.readFloat(); } void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(yearsOfExperience); dest.writeTypedList(skillSet); dest.writeFloat(favoriteFloat); } int describeContents() { return 0; } static final Parcelable.Creator<ParcelableDeveloper> CREATOR = new Parcelable.Creator<ParcelableDeveloper>() { ParcelableDeveloper createFromParcel(Parcel in) { return new ParcelableDeveloper(in); } ParcelableDeveloper[] newArray(int size) { return new ParcelableDeveloper[size]; } }; static class Skill implements Parcelable { String name; boolean programmingRelated; Skill(Parcel in) { this.name = in.readString(); this.programmingRelated = (in.readInt() == 1); } @Override void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(programmingRelated ? 1 : 0); } static final Parcelable.Creator<Skill> CREATOR = new Parcelable.Creator<Skill>() { Skill createFromParcel(Parcel in) { return new Skill(in); } Skill[] newArray(int size) { return new Skill[size]; } }; @Override int describeContents() { return 0; } } }

根據 google 工程師的說法,這些程式碼將會執行地特別快。原因之一就是我們已經清楚地知道了序列化的過程,而不需要使用反射來推斷。同時為了更快地進行序列化,物件的程式碼也需要高度優化。

因此,很明顯實現Parcelable並不容易。實現Parcelable介面需要寫大量的模板程式碼,這使得物件程式碼變得難以閱讀和維護。

速度測試

當然,我們還是想知道到底Parcelable相對於Serializable要快多少。

測試方法

  • 通過將一個物件放到一個bundle裡面然後呼叫Bundle#writeToParcel(Parcel, int)方法來模擬傳遞物件給一個activity的過程,然後再把這個物件取出來。
  • 在一個迴圈裡面執行1000 次。
  • 兩種方法分別執行10次來減少記憶體整理,cpu被其他應用佔用等情況的干擾。
  • 參與測試的物件就是上面程式碼中的SerializableDeveloper 和 ParcelableDeveloper。
  • 在多種Android軟硬體環境上進行測試
    • LG Nexus 4 – Android 4.2.2
    • Samsung Nexus 10 – Android 4.2.2
    • HTC Desire Z – Android 2.3.3

結果

parcelable-vs-serializable

parcelable-vs-serializable

Nexus 10
Serializable: 1.0004ms, Parcelable: 0.0850ms – 提升10.16倍。

Nexus 4
Serializable: 1.8539ms – Parcelable: 0.1824ms – 提升11.80倍。

Desire Z
Serializable: 5.1224ms – Parcelable: 0.2938ms – 提升17.36倍。

由此可以得出: Parcelable 比 Serializable快了10多倍。有趣的是,即使在Nexus 10這樣效能強悍的硬體上,一個相當簡單的物件的序列化和反序列化的過程要花將近一毫秒。

總結

如果你想成為一個優秀的軟體工程師,你需要多花點時間來實現 Parcelable ,因為這將會為你物件的序列化過程快10多倍,而且佔用較少的資源。

但是大多數情況下, Serializable 的龜速不會太引人注目。你想偷點懶就用它吧,不過要記得serialization是一個比較耗資源的操作,儘量少使用。

如果你想要傳遞一個包含許多物件的列表,那麼整個序列化的過程的時間開銷可能會超過一秒,這會讓螢幕轉向的時候變得很卡頓。