1. 程式人生 > >android 支援的序列化-------Serializable和Parcelble

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即可。然後 通過物件輸出流就可以實現序列化,通過物件輸入流就可以實現反序列化。但是,需要注意的是:

  1. 靜態成員不輸入單個物件,不參與序列化;
  2. 使用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操作,效率低,主要用來序列化物件到儲存裝置或者網路傳送等。