android 支援的序列化-------Serializable和Parcelble
android 支援兩種序列化:Serializable和Parcelble。前者是Java語言自帶的序列化機制,通過讀寫檔案實現物件的序列化和反序列化;後者是Android Os實現的序列化,它是通過讀寫記憶體來實現序列化,從而實現物件的傳遞。下面,就這兩種方式詳細說明。
Serializable
Serializable是Java提供的一個空介面。物件要想實現序列化,只需要如下:
public class SerializableClass implements Serializable{ private static final long serialVersionUID = 1L; ...... }
繼承自Serializable,並且提供一個serialVersionUID即可。然後 通過物件輸出流就可以實現序列化,通過物件輸入流就可以實現反序列化。但是,需要注意的是:
- 靜態成員不輸入單個物件,不參與序列化;
- 使用transient關鍵字修飾的成員不參與序列化。
serialVersionUID用來在反序列化的時候做校驗。反序列化時,會檢測檔案中的serialVersionUID和類的serialVersionUID是否一致,如果一致,則說明可以進行序列化,否則說明類的版本不匹配,不能進行序列化。
如果不指定serialVersionUID,在進行序列化的時候,會預設根據當前類的結構,生成hash值作為serialVersionUID寫到檔案,在反序列化的時候,同樣會生成類的hash值並和檔案中序列化寫入的serialVersionUID進行比較,如果一致就可以序列化,否則不可以。這樣會造成一個問題:如果序列化之後,類有了修改,那麼,此時預設生成的hash值和之前序列化寫入的hash值不匹配,導致無法序列化。
為了克服這個問題,最好手動指定serialVersionUID,或者由IDE工具自動生成。這樣的好處是,及時序列化後,類做了小的改動,比如增加或刪除了成員變數,那麼,還是可以反序列恢復物件。但是,如果類的結構發生了非常規的改變,則無法反序列化,比如,修改了類名等。
Parcelable
Parcelable同樣也是一個介面。它主要完成序列化和反序列化以及內容描述功能。User是一個Parcelable類:
public class User implements Parcelable{ public int userId; public String userName; public boolean isMale; public Book book; public User() { } public User(int userId, String userName, boolean isMale) { this.userId = userId; this.userName = userName; this.isMale = isMale; } /** * 噹噹前物件中含有檔案描述符時,返回1,其他時候返回0; * @return */ public int describeContents() { return 0; } /** * 通過Parcel的write方法,實現序列化 * @param out * @param flags */ public void writeToParcel(Parcel out, int flags) { out.writeInt(userId); out.writeString(userName); out.writeInt(isMale ? 1 : 0); out.writeParcelable(book, 0); } /** * 實現反序列化 */ public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() { /** * 通過Parcel的read方法,實現反序列化生成一個物件 * @param in * @return */ public User createFromParcel(Parcel in) { return new User(in); } /** * 實現反序列化生成一個數組 * @param size * @return */ public User[] newArray(int size) { return new User[size]; } }; private User(Parcel in) { userId = in.readInt(); userName = in.readString(); isMale = in.readInt() == 1; /** * book是一個Parcelable物件,反序列需要傳遞一個ClassLoader,否則會報錯。 */ book = in.readParcelable(Thread.currentThread().getContextClassLoader()); } }
其中,序列化時通過writeToParcel()實現,反序列化通過CREATOR提供,內容描述由describeContents提供。注意事項見註釋。系統為我們提供了很多Parcelable類:Intent,Bundle和BitMap等。同時,List和Map也可以是Parcelable的,當且僅當它們裡面的每個物件都是Parcelable的。
Parcelable和Serializable雖然都是用來序列化的,但是,二者有較大差別。前者用來實現記憶體序列化,用來在Binder之間傳遞物件,效率較高,但是使用麻煩。後者是通過讀寫檔案來實現序列化,需要大量的I/O操作,效率低,主要用來序列化物件到儲存裝置或者網路傳送等。