Android中的Serializable和Parcelable序列化

Serializable和Parcelable接口都可以完成對象的序列化過程,在Android中當我們需要通過Intent和Binder傳輸數據時,我們要傳輸的對象就需要使用Serializable和Parcelable接口。對象的序列化可以使我們能夠將對象持久化到存儲設備上或者通過網絡傳輸到其他客戶端,這個時候也需要使用Serializable來完成對象的序列化。

Serializable接口:

Serializable接口是Java所提供的一個序列化接口,它是一個空接口,爲對象提供標準的序列化和反序列化操作,使用Serializable接口實現序列化非常簡單,只需要在類的聲明中指定實現Serializable接口即可,此時就可以自動實現默認的序列化過程。實現Serializable接口時會自動生成一個類似下面的標識:

private static final long serialVersionUID = 5778823142350671979L;
在實際使用中,甚至連這個serialVersionUID 也不是必須的,不指定這個serialVersionUID 也可以實現序列化,但是這對序列化過程會產生影響,我們先來看一個例子:
public class People implements Serializable{

    private String name;
    private String address;
    private int age;

    public People(String name, String address, int age) {
        this.name = name;
        this.address = address;
        this.age = age;
    }
}
使用Serializable接口實現對象的序列化比較簡單,很多工作都別系統自動完成了。只需要使用ObjectOutpuStream和ObjectInputStream即可輕鬆實現:

public void test(){
        People people = new People("Jack", "中國武漢", 30);
        try {
            //序列化過程
            ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(byteOut);
            out.writeObject(people);
            out.close();

            //反序列化過程
            ObjectInputStream in = new ObjectInputStream(
                    new ByteArrayInputStream(byteOut.toByteArray()));
            People clonePeople = (People) in.readObject();
            in.close();
            byteOut.close();
            Log.i("tag",clonePeople.getName() + clonePeople.getAddress() + clonePeople.getAddress());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
在上述過程總我們並沒有指定serialVersionUID 也實現了對象的序列化,那我們在開發的時候到底要不要指定呢?如果指定的話,它又代表什麼意思?系統既然提供了這個serialVersionUID ,那麼它肯定有它的作用。這個serialVersionUID 是用來輔助序列化和反序列化過程的,原則上序列化後的數據中的serialVersionUID 只有和當前類的serialVersionUID 相同才能正常的被反序列化。serialVersionUID 的工作機制是這樣的 :序列化的時候系統會把當前類的serialVersionUID 寫入序列化的文件中(也可以是其他的),當反序列化的時候系統會去檢測文件中的serialVersionUID ,看他是否和當前類的serialVersionUID 一致,如果一致就說明序列化的類的版本和當前類的版本是相同的,這個時候可以成功反序列化,否則就說明當前類和序列化的類相比發生了某些變化,會報錯。

以上便是使用Serializable實現對象的序列化和反序列化,但是要注意:①靜態成員變量屬於類不屬於對象,所以不會參與序列化過程;②transient關鍵字標記的成員變量不參與序列化過程。


Parcelable接口:

在Android中也提供了新的序列化方式,就是使用Parcelable接口,只要實現這個接口,一個類的對象就可以實現序列化並可以通過Intent和Binder傳遞,使用Parcelable接口來實現對象的序列化,過程稍微複雜一些。例如:

public class Address implements Parcelable{

    private String province;
    private String city;
    private String town;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeString(province);
        out.writeString(city);
        out.writeString(town);
    }

    public static final Parcelable.Creator<Address> CREATOR = new Parcelable.Creator<Address>(){
        @Override
        public Address createFromParcel(Parcel in) {
            return new Address(in);
        }

        @Override
        public Address[] newArray(int size) {
            return new Address[size];
        }
    };

    private Address(Parcel in){
        province = in.readString();
        city = in.readString();
        town = in.readString();
    }

    public Address() {
    }
    ......getter,setter
}
public class People implements Parcelable{

    private String name;
    private String sex;
    private int age;

    private Address address;

    public People() {
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(age);
        out.writeString(name);
        out.writeString(sex);
        out.writeParcelable(address,0);
    }

    public static final Parcelable.Creator<People> CREATOR = new Parcelable.Creator<People>(){
        @Override
        public People createFromParcel(Parcel in) {
            return new People(in);
        }

        @Override
        public People[] newArray(int size) {
            return new People[size];
        }
    };

    private People(Parcel in){
        name = in.readString();
        sex = in.readString();
        age = in.readInt();
        address = in.readParcelable(Thread.currentThread().getContextClassLoader());
    }
    .......getter,setter
}
從上面的代碼可以看出,在序列化過程中需要實現的功能有序列化、反序列化和內容描述。序列化功能由writeToParcel方法來完成,最終是通過調用Parcel的一系列write方法完成的;反序列化功能由CREATOR來完成,其內部實現了創建序列化對象和數組;內容描述功能由describeContents方法來完成,幾乎在所有情況下這個方法都返回0,僅噹噹前對象中存在文件描述符時返回1。注意:在People(Parcel  in)方法中,因爲address是另一個可序列化的對象,所以它的反序列化過程需要傳遞當前線程的上下文類加載器。

List和Map也可以序列化,但是前提是它們裏面的每個元素都是可序列化的。


二者的區別:

既然Parcelable和Serializable都能實現序列化並且都可以用於Intent間的數據傳遞,那我們如何選擇呢。Serializable是Java中的序列化接口,它使用起來簡單但是在序列化和反序列化的過程中都要進行大量的I/O操作。而Parcelable是Android中的序列化方式,雖然使用麻煩,但是它的效率高,它也是Android推薦的序列化方式。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章