Android中實(shí)現(xiàn)序列化有兩個(gè)選擇:一個(gè)是實(shí)現(xiàn)Serializable接口贷洲,Java提供的一個(gè)序列化接口寇损;另一個(gè)是實(shí)現(xiàn)Parcelable接口,Android特有的序列化接口,效率比實(shí)現(xiàn)Serializable接口高效移袍,可用于Intent數(shù)據(jù)傳遞,也可以用于進(jìn)程間通信(IPC)老充。
序列化和反序列化
序列化:用來(lái)處理對(duì)象流的機(jī)制葡盗,所謂對(duì)象流就是將對(duì)象的內(nèi)容進(jìn)行流化。方便對(duì)流化后的對(duì)象進(jìn)行讀寫操作啡浊,也可在網(wǎng)絡(luò)間傳輸觅够。簡(jiǎn)單來(lái)說(shuō)是一種將對(duì)象以一連串的字節(jié)描述的過(guò)程。
反序列化:將流化后的對(duì)象重新構(gòu)成對(duì)象的過(guò)程巷嚣。
序列化應(yīng)用場(chǎng)景
- 永久性保存對(duì)象喘先,保存對(duì)象的字節(jié)序列到本地文件中
- 通過(guò)序列化對(duì)象在網(wǎng)絡(luò)中傳輸
- 通過(guò)序列化在進(jìn)程間傳遞對(duì)象
Serializable序列化ID:
序列化ID serialVersionUID的值可以是固定的1L,也可以是隨機(jī)生成一個(gè)不重復(fù)的long類型數(shù)據(jù)廷粒,甚至可以不聲明也可以實(shí)現(xiàn)序列化窘拯。但是會(huì)對(duì)反序列化過(guò)程產(chǎn)生影響,因?yàn)椴煌男蛄谢疘D之間不能進(jìn)行序列化和反序列化坝茎。
Serializable實(shí)現(xiàn)序列化步驟
創(chuàng)建某些OutputStream對(duì)象:OutputStream outputStream = new FileOutputStream("output.txt");
將其封裝到ObjectOutputStream對(duì)象內(nèi):ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
調(diào)用writeObject()即可完成對(duì)象的序列化涤姊,并將其發(fā)送給OutputStream:objectOutputStream.writeObject(Object);
關(guān)閉資源:objectOutputStream.close()和outputStream.close();
Serializable實(shí)現(xiàn)反序列化步驟
創(chuàng)建某些InputStream對(duì)象:InputStream inputStream = new FileInputStream("output.txt");
將其封裝到ObjectInputStream對(duì)象內(nèi):ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
調(diào)用readObject()即可完成對(duì)象的反序列化:object = objectInputStream.readObject();
關(guān)閉資源:objectInputStream.close()和inputStream.close();
注意:
- 靜態(tài)變量屬于類不屬于對(duì)象,所以不會(huì)參與序列化過(guò)程嗤放。
- 用transient關(guān)鍵字標(biāo)記的成員變量不參與序列化過(guò)程思喊。(通過(guò)用這個(gè)關(guān)鍵字可以控制想要序列化的成員變量)
Serializable代碼實(shí)例:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(String name, int age) {
this.name= name;
this.age= age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// Serializable:把對(duì)象序列化
public static void writeSerializableObject() {
try {
Person person = new Person("Mary", 18);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("output.txt"));
objectOutputStream.writeObject(person);
objectOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// Serializable:反序列化對(duì)象
public static void readSerializableObject() {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("output.txt"));
Person person = (Person) objectInputStream.readObject();
objectInputStream.close();
System.out.println("name = " + person.getName() + ", age = " + person.getAge());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
Parcelable接口定義
public interface Parcelable
{
//內(nèi)容描述接口,基本不用管
public int describeContents();
//寫入接口函數(shù)次酌,打包
public void writeToParcel(Parcel dest, int flags);
//讀取接口恨课,目的是要從Parcel中構(gòu)造一個(gè)實(shí)現(xiàn)了Parcelable的類的實(shí)例處理。因?yàn)閷?shí)現(xiàn)類在這里還是不可知的岳服,所以需要用到模板的方式剂公,繼承類名通過(guò)模板參數(shù)傳入
//為了能夠?qū)崿F(xiàn)模板參數(shù)的傳入,這里定義Creator嵌入接口,內(nèi)含兩個(gè)接口函數(shù)分別返回單個(gè)和多個(gè)繼承類實(shí)例
public interface Creator<T>
{
public T createFromParcel(Parcel source);
public T[] newArray(int size);
}
}
Parcelable實(shí)現(xiàn)序列化步驟
實(shí)現(xiàn)Parcelable接口
重寫writeToParcel方法吊宋,將你的對(duì)象序列化為一個(gè)Parcel對(duì)象诬留,即:將類的數(shù)據(jù)寫入外部提供的Parcel中,打包需要傳遞的數(shù)據(jù)到Parcel容器保存,以便從 Parcel容器獲取數(shù)據(jù)
重寫describeContents方法文兑,內(nèi)容接口描述盒刚,默認(rèn)返回0就可以
實(shí)例化靜態(tài)內(nèi)部對(duì)象CREATOR實(shí)現(xiàn)接口Parcelable.Creator。需重寫本接口中的兩個(gè)方法:createFromParcel(Parcel in) 實(shí)現(xiàn)從Parcel容器中讀取傳遞數(shù)據(jù)值绿贞,封裝成Parcelable對(duì)象返回邏輯層因块,newArray(int size) 創(chuàng)建一個(gè)類型為T,長(zhǎng)度為size的數(shù)組籍铁,僅一句話即可(return new T[size])涡上,供外部類反序列化本類數(shù)組使用。
public static final Parcelable.Creator<T> CREATOR
Parcelable代碼實(shí)例:
public class Person implements Parcelable
{
private String name;
private String sex;
private int age;
public int describeContents()
{
return 0;
}
public void writeToParcel(Parcel out, int flags)
{
out.writeString(name);
out.writeString(sex);
out.writeInt(age);
}
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>()
{
public Person createFromParcel(Parcel in)
{
return new Person(in);
}
public Person[] newArray(int size)
{
return new Person[size];
}
};
private Person(Parcel in)
{
name = in.readString();
sex = in.readString();
age = in.readInt();
}
}
Serializable和Parcelable對(duì)比
Serializable實(shí)現(xiàn)較簡(jiǎn)單拒名,只需要implements Serializable即可吩愧,系統(tǒng)會(huì)自動(dòng)將其序列化;而Parcelable的實(shí)現(xiàn)增显,不僅需要implements Parcelable雁佳,還需要在類中添加一個(gè)靜態(tài)成員變量CREATOR,這個(gè)變量需要實(shí)現(xiàn) Parcelable.Creator接口同云。
使用內(nèi)存時(shí)糖权,Parcelable比Serializable性能高,推薦使用Parcelable炸站。
Parcelable不能使用在要將數(shù)據(jù)存儲(chǔ)在磁盤上的情況星澳,因?yàn)镻arcelable不能很好的保證數(shù)據(jù)的持續(xù)性在外界有變化的情況下。盡管Serializable效率低點(diǎn)旱易,但此時(shí)還是建議使用Serializable 禁偎。