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 介面是一種標識介面(
這種方法的缺點是使用了反射,序列化的過程較慢。這種機制會在序列化的時候建立許多的臨時物件,容易觸發垃圾回收。
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
結果
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是一個比較耗資源的操作,儘量少使用。
如果你想要傳遞一個包含許多物件的列表,那麼整個序列化的過程的時間開銷可能會超過一秒,這會讓螢幕轉向的時候變得很卡頓。