Android之IPC3————序列化
Android之IPC3————序列化
文章目錄
一.前言
說起序列化,大家應該都不會陌生,在Android中的應用也比較多,特別是在Activity直接傳遞物件時。就需要使用序列化,我一般是使用Serialization對物件進行序列化,然後進行傳遞。而在上篇文章中,在使用AIDL時,對跨程序傳遞的物件也進行了序列化,當時我們使用的是Parcelable。它也是一種序列化的方法。
在這篇文章裡,我分別介紹一下兩者的使用以及區別
二.序列化
1.什麼是序列化
序列化 (Serialization)將物件的狀態資訊轉換為可以儲存或傳輸的形式的過程。在序列化期間,物件將其當前狀態寫入到臨時或永續性儲存區。以後,可以通過從儲存區中讀取或反序列化物件的狀態,重新建立該物件。
簡單來說就是講物件進行儲存,在下次使用時可以順利還原該物件。
2.序列化儲存的內容
物件是類的一個例項,一個類中包含變數和函式兩部分。同一個類的不同物件只是變數不同,所以序列化是隻儲存物件的變數部分。同樣,由於靜態變數是由一個類的各個物件共用的,所以序列化過程中也不儲存。
3.序列化的作用
序列化的用途主要有三個:
- 物件的持久化,物件持久化是指延長物件的存在時間,比如通過序列化功能,將物件儲存在檔案中,就可以延長物件的存在時間,在下次執行程式是再恢復該物件
- 物件複製,通過序列化後,將物件儲存在記憶體中,可以在用過次資料得到多個物件的副本
- 物件傳輸,通過序列化,可以通過網路傳遞物件,以及跨程序通訊。
三.Serialization
1.實現介面
使用Serialization進行序列化,是比較簡單的一件事,只要將需要序列化的類實現Serialization介面,並宣告一個SerialVersionUID即可,甚至SerialVersionUID也不是必須的。沒有它依然可以序列化,只是對反序列化造成影響
下面我們宣告一個類,並將它實現Serialization介面
public class User implements Serializable {
private int userId;
private String userName;
private boolean isMale;
public User(int UserId,String UserName,boolean IsMale){
userId = UserId;
userName = UserName;
isMale = IsMale;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public boolean isMale() {
return isMale;
}
public void setMale(boolean male) {
isMale = male;
}
}
2.序列化和反序列化
public class Main {
public static void main(String[] args) {
//序列化過程
User user = new User(1,"shucheng",true);
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
out.writeObject(user);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
//反序列化過程
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
User newUser = (User)in.readObject();
in.close();
System.out.println(newUser.getUserName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
上面就是採用Serializable方式實現序列化物件的典型過程。恢復後的物件和之前的物件內容一樣,但並不是同樣的物件
3.SerialVersionUID的作用
SerialVersionUID是序列化的機制判斷類的版本一致性的。進行反序列化時,JVM會把傳來的位元組流中的serialVersionUID與本地相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常,即是InvalidCastException。
serialVersionUID有兩種顯示的生成方式:
一是預設的1L,比如:private static final long serialVersionUID = 1L;
二是根據類名、介面名、成員方法及屬性等來生成一個64位的雜湊欄位,比如:
private static final long serialVersionUID = xxxxL;
當序列化前後的SerialVersionUID發生變化,對應的類發生變化時,有以下幾種情況
情況一:假設User類序列化之後,從A端傳輸到B端,然後在B端進行反序列化。在序列化Person和反序列化Person的時候,A端和B端都需要存在一個相同的類。如果兩處的serialVersionUID不一致,會產生什麼錯誤呢?
結果:結果報錯
情況二:假設兩處serialVersionUID一致,如果A端增加一個欄位,然後序列化,而B端不變,然後反序列化,會是什麼情況呢?
結果:執行序列化,反序列化正常,但是A端增加的欄位丟失(被B端忽略)。
情況三:假設兩處serialVersionUID一致,如果B端減少一個欄位,A端不變,會是什麼情況呢?
結果:序列化,反序列化正常,B端欄位少於A端,A端多的欄位值丟失(被B端忽略)。
情況四:假設兩處serialVersionUID一致,如果B端增加一個欄位,A端不變,會是什麼情況呢?
結果:反序列化正常,B端新增加的int欄位被賦予了預設值0。
四.Parcelable
前面介紹了序列化和Java中使用Serializable來實現序列化。我們繼續來看android中的序列化Parcelable
1.為什麼使用Parcelable
在Android中是可以使用Serializable進行序列化,而且使用起來也很簡單,為什麼Android要自己在實現一個Parcelable方法。因為Serializable是Java中的序列化方法,雖然很簡單但是開銷很大。序列化和反序列化中需要大量的I/O操作。
Parcelable是Android中序列化的實現,它的缺點是使用起來稍微麻煩些,但是效率很高,這是Android推薦的序列化方式。Parcelable主要作用在記憶體序列化上。所以如果用了進行Intent和Binder傳輸,建議使用Parcelable。如果用來將物件序列化到本地或者用來進行網路傳輸時,還是推薦使用Serializable。
2.使用
以上一篇文章的序列化的類為例,在裡面也為其中的方法進行了註釋。
public class Book implements Parcelable {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "書名:"+name +",價格"+price;
}
public Book() {
}
/**
* 返回當前物件的描述內容,如果含有檔案描述符,返回1,否則返回0
* @return
*/
@Override
public int describeContents() {
return 0;
}
/**
* 將當前物件寫入序列化結構中
* @param dest
* @param flags:有兩種0/1 為1時表示當前物件需要作為返回值返回,不能立即釋放資源,大部分情況下為0
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(price);
}
/**
* 從序列化後的物件中建立原始物件
* @param in
*/
protected Book(Parcel in) {
name = in.readString();
price = in.readInt();
}
public static final Creator<Book> CREATOR = new Creator<Book>() {
/**
* 從序列化後的物件中建立原始物件
* @param in
* @return
*/
@Override
public Book createFromParcel(Parcel in) {
return new Book(in);
}
/**
* 建立指定長度的原始物件陣列
* @param size
* @return
*/
@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
}
五.參考資料
《Android藝術開發探索》
Java序列化(Serialization)的理解
Java 的序列化 (Serialization)教程
java類中serialversionuid 作用