Android 的序列化方式 Parcelable
Parcel 介紹:Parcel 內(nèi)部包裝了可序列化的數(shù)據(jù)缠沈,可以在 Binder 中自由傳輸
Parcelable 是一個(gè)接口儿倒,只要實(shí)現(xiàn)這個(gè)接口掰吕,一個(gè)類(lèi)的對(duì)象就可以實(shí)現(xiàn)序列化并可以通過(guò) Intent 和 Binder 傳遞果覆。
package com.renxl.touchevent.scrollview;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
private String name;
private int price;
private Category category;
protected Book(Parcel in) {
name = in.readString();
price = in.readInt();
category = in.readParcelable(Category.class.getClassLoader());
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(price);
dest.writeParcelable(category, flags);
}
}
由上段代碼可以看出序列化過(guò)程需要實(shí)現(xiàn)的功能有 序列化,反序列化殖熟,內(nèi)容描述 三部分
一局待、序列化功能
序列化功能是由 writeToParcel 方法完成的,是通過(guò) Parcel 的一些了 write 方法完成的菱属。
注意:序列化的類(lèi)的成員屬性也必須是可序列化的钳榨。Parcel 的 writeParcelable 方法中除了可序列化的屬性,還需要添加 int 類(lèi)型的 flag 參數(shù)纽门,表示該對(duì)象應(yīng)以何種方式寫(xiě)入薛耻,一般傳 writeToParcel 方法的 flag 參數(shù)或者0。
二赏陵、反序列化功能
反序列化過(guò)程由 CREATOR 來(lái)完成饼齿,其內(nèi)部表明了如何創(chuàng)建序列化對(duì)象和序列化對(duì)象的數(shù)組,創(chuàng)建序列化對(duì)象使用了序列化對(duì)象的參數(shù)為 Parcel 的構(gòu)造方法蝙搔,該方法中根據(jù)序列化過(guò)程得到的 Parcel 對(duì)象的 read 系列方法將序列化對(duì)象的內(nèi)容還原完成反序列化過(guò)程缕溉。
如果序列化類(lèi)的屬性有可序列化對(duì)象,在反序列化過(guò)程中需要傳遞當(dāng)前線程的上下文類(lèi)加載器吃型,否則會(huì)報(bào)無(wú)法找到類(lèi)的錯(cuò)誤证鸥。
三、內(nèi)容描述功能
內(nèi)容描述功能由 describeContents 完成勤晚,幾乎所有情況該方法都返回 0 枉层,僅當(dāng)當(dāng)前對(duì)象中存在的文件描述符時(shí)此方法返回 1 。
文件描述符: 文件描述符在形式上是一個(gè)非負(fù)整數(shù)赐写。實(shí)際上返干,它是一個(gè)索引值,指向內(nèi)核為每一個(gè)進(jìn)程所維護(hù)的該進(jìn)程打開(kāi)文件的記錄表血淌。當(dāng)程序打開(kāi)一個(gè)現(xiàn)有文件或者創(chuàng)建一個(gè)新文件時(shí)矩欠,內(nèi)核向進(jìn)程返回一個(gè)文件描述符。在程序設(shè)計(jì)中悠夯,一些涉及底層的程序編寫(xiě)往往會(huì)圍繞著文件描述符展開(kāi)癌淮。但是文件描述符這一概念往往只適用于UNIX、Linux這樣的操作系統(tǒng)沦补。
Android 系統(tǒng)提供的實(shí)現(xiàn)了 Parcelable 的類(lèi)乳蓄,Intent,Bundle夕膀,Bitmap等虚倒,List 和 Map 也可以序列化美侦,前提是里面的內(nèi)容都可以序列化。
序列化方式 Serializable 接口
Java 中提供的序列化方式魂奥,實(shí)現(xiàn) Serializable 接口菠剩,是一個(gè)空接口,為對(duì)象提供了標(biāo)準(zhǔn)的序列化和反序列化操作耻煤。
只需要在類(lèi)的聲明中指定 private static final long serialVersionUID = 123423432234L 即可具壮,該值并不是必須的
serialVersionUID 作用為輔助序列化和反序列化過(guò)程,反序列化時(shí)序列化數(shù)據(jù)中的 serialVersionUID 和當(dāng)前類(lèi)的 serialVersionUID 相同是才能成功哈蝇,不相同則會(huì)反序列化是吧棺妓,程序 crash。類(lèi)中該值不指定時(shí)可以根據(jù)當(dāng)前類(lèi)的結(jié)構(gòu)自動(dòng)生成 hash 炮赦,不過(guò)當(dāng)類(lèi)結(jié)構(gòu)變化時(shí)反序列化會(huì)失敗怜跑。如果指定,就算類(lèi)的結(jié)構(gòu)發(fā)生改變也會(huì)最大限度的恢復(fù)數(shù)據(jù)吠勘。
還有兩點(diǎn)點(diǎn)需要注意
- 靜態(tài)成員變量屬于類(lèi)不屬于對(duì)象妆艘,所以不參與序列化過(guò)程,反序列化得到的對(duì)象也可以使用該屬性看幼,但原理是因?yàn)槭褂玫氖穷?lèi)的靜態(tài)變量
- 被 transient 修飾的成員不參與序列化批旺,反序列化后也不會(huì)得到 transient 修飾的成員
Parcelable 和 Serializable 區(qū)別
- 兩者都可以實(shí)現(xiàn)序列化并且都可以用于 Intent 間數(shù)據(jù)傳遞
- Serializable 是 Java 中的序列化接口,使用簡(jiǎn)單但是開(kāi)銷(xiāo)很大诵姜,序列化和反序列化過(guò)程需要很多 I/O 操作
- Parcelable 是 Android 中的序列化方式汽煮,更適合用在 Android 中,確定是使用麻煩棚唆,但是效率很高暇赤。Android 中首選 Parcelable
- Parcelable 主要用于 Android 跨進(jìn)程通信時(shí)在對(duì)內(nèi)存數(shù)據(jù)的序列話,跨進(jìn)程傳輸?shù)臄?shù)據(jù)是必須序列化的宵凌,Parcelable 更方便
- 將對(duì)象序列化到設(shè)備的本地文件或者網(wǎng)絡(luò)傳輸鞋囊,建議使用 Serializable,