Serializable和Parcelable是什么?
Serializable和Parcelable都是一種將對象序列化的接口(序列化,表示將一個對象轉換成可存儲或可傳輸的狀態。序列化后的對象可以在網絡上進行傳輸,也可以存儲到本地),Serializable是java中提供的,而Parcelable是Android中提供的。
準備工作
寫一個User類,下面會分別使這個類接入Serializable和Parcelable接口。
public class User {
private static final String TAG = "User";
private String name;
private int age;
//為了省略篇幅,構造方法,getter和setter省略不寫了
}
在MainActivity的onCreate()方法中加入下面的代碼
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("user", new User("test", 123));
startActivity(intent);
創建一個SecondActivity,同樣在onCreate()方法中加入下面的代碼
User user = (User) getIntent().getSerializableExtra("user");
Log.i(TAG, user.getName() + " " + user.getAge() + "");
Serializable的使用
在完成了上面的代碼后,你會發現MainActivity里如圖所示的這一行報錯了,這是因為intent不能直接put對象進去,需要對象實現Serializable或者Parcelable接口才可以。
這里我們直接在User類的聲明后加上
implements Serializable
就可以了,之后就發現不再報錯,運行程序,查看log,發現User對象成功傳遞了。Parcelable的使用
這次我們讓User類實現Parcelable接口,接入接口之后我們需要重寫兩個方法。
public class User implements Parcelable {
private static final String TAG = "User";
private String name;
private int age;
//同樣省略了構造方法,getter和setter
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getName());
dest.writeInt(getAge());
}
}
describeContents()返回當前對象的內容描述。如果含有文件描述符,返回1,否則返回0,幾乎所有的情況都返回0。
writeToParcel()是將當前對象寫入一個Parcel中,一般是將當前對象的屬性值通過writexxxx()方法寫入。上面的代碼就是分別將User對象的name和age寫入。
除了上面的,我們還需要寫一個Creator用來返回User對象,寫法如下邊所示,一般newArray()的返回值都是new User[size]。
在createFromParcel()方法里你可以直接寫return new User(source.readString(),source.readInt());
,但更標準的寫法是再寫一個構造方法,這個構造方法的參數為Parcel對象,然后在這個構造方法里對對象的屬性進行賦值。
需要注意的是,當一個對象中有多個同種類型的變量時,通過readxxxx()方法獲取的值和你writexxxx()方法寫入的順序是一致,比方說我現在有一個類只有三個int類型的變量,分別為num1,num2,num3,然后我在 writeToParcel()方法里依次寫入了num1、2、3,那么我的三個read的值也分別是num1、2、3。
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel source) {
return new User(source);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
private User(Parcel in) {
this.name = in.readString();
this.age = in.readInt();
}
我們把Second里的User對象的聲明改為User user = getIntent().getParcelableExtra("user");
,運行程序,發現程序成功運行。
Serializable和Parcelable的區別
Parcelable的性能比Serializable好,在內存開銷方面較小,所以在內存間數據傳輸時推薦使用Parcelable,如activity間傳輸數據,而Serializable可將數據持久化方便保存,所以在需要保存或網絡傳輸數據時選擇Serializable,因為android不同版本Parcelable可能不同,所以不推薦使用Parcelable進行數據持久化
一個有意思的現象
既然Serializable與Parcelable都是接口,那么說明我們的一個類可以同時接入這兩個接口,當我們這么做時,會發生什么現象呢?
我們使User類同時接入這兩個接口,并在writeToParcel()方法里加一句logLog.i(TAG, "used writeToParcel");
這時我們發現MainActivity的putExtra()方法報錯,因為這時編譯器無法判斷到底是使用Serializable還是Parcelable,在這里我們為了驗證這個有意思的現象,把User強轉為Serializable,并且在SecondActivity里也用Serializable接收。
運行程序,發現一個有意思的現象出現了,我們同樣能夠接收到對象,但是通過篩選log發現
不是很懂為什么會出現這種情況,希望有大佬能說一下。