Android開發當中Parcelable,Serializable介面的使用
Activity之間傳資料時,為了避免麻煩,往往會將一些值封裝成物件,然後將整個物件傳遞過去。
對於Android來說傳遞複雜型別,主要是將自己的類轉換為基礎的位元組陣列,Activity之間傳遞資料是通過Intent實現的。
Android序列化物件主要有兩種方法,實現Serializable介面、或者實現Parcelable介面。實現Serializable介面是Java SE本身就支援
的,而Parcelable是Android特有的功能,效率比實現Serializable介面高,而且還可以用在程序間通訊(IPC)中。
實現Serializable介面非常簡單,宣告一下就可以了。而實現Parcelable介面稍微複雜一些,但效率更高,推薦用這種方法提高效能。
a)當你想把的記憶體中的物件寫入到硬碟的時候;
b)當你想用套接字在網路上傳送物件的時候;
c)當你想通過RMI傳輸物件的時候;
再稍微解釋一下:
a)比如說你的記憶體不夠用了,那計算機就要將記憶體裡面的一部分物件暫時的儲存到硬碟中,等到要用的時候再讀入到
記憶體中,硬碟的那部分儲存空間就是所謂的虛擬記憶體。在比如過你要將某個特定的物件儲存到檔案中,我隔幾天在把
它拿出來用,那麼這時候就要實現Serializable介面;
b)在進行java的Socket程式設計的時候,你有時候可能要傳輸某一類的物件,那麼也就要實現Serializable介面;
最常見的你傳輸一個字串,它是JDK裡面的類,也實現了Serializable介面,所以可以在網路上傳輸。
c)如果要通過遠端的方法呼叫(RMI)去呼叫一個遠端物件的方法,如在計算機A中呼叫另一臺計算機B的物件的方法,
那麼你需要通過JNDI服務獲取計算機B目標物件的引用,將物件從B傳送到A,就需要實現序列化介面。
1、什麼是Parcelable介面呢?
1)Parcelable,定義了將資料寫入Parcel,和從Parcel中讀出的介面。一個實體(用類來表示),如果需要封裝到訊息中去,就必須實現這一介面,實現了這一介面,該實體就成為“可打包的”了。
2)Parcelable介面的定義:
public interface Parcelable { //內容描述介面,基本不用管 public int describeContents(); //寫入介面函式,打包 public void writeToParcel(Parcel dest, int flags); //讀取介面,目的是要從Parcel中構造一個實現了Parcelable的類的例項處理。因為實現類在這裡還是不可知的,所以需要用到模板的方式, <span style="font-family:Arial;"> </span>//繼承類名通過模板引數傳入。 //為了能夠實現模板引數的傳入,這裡定義Creator嵌入介面,內含兩個介面函式分別返回單個和多個繼承類例項。 public interface Creator<T> { public T createFromParcel(Parcel source); public T[] newArray(int size); } }
二 至於選取哪種可參考下面的原則:
1.在使用記憶體的時候,Parcelable 類比Serializable效能高,所以推薦使用Parcelable類。
2.Serializable在序列化的時候會產生大量的臨時變數,從而引起頻繁的GC。
3.Parcelable不能使用在要將資料儲存在磁碟上的情況,因為Parcelable不能很好的保證資料的持續性在外界有變化的情況下。儘管Serializable效率低點, 也不提倡用,但在這種情況下,還是建議你用Serializable 。
Parcelable介面的作用:實現了Parcelable介面的例項可以將自身的狀態資訊(狀態資訊通常指的是各成員變數的值)寫入Parcel,
也可以從Parcel中恢復其狀態。 Parcel用來完成資料的序列化傳遞。下面就介紹一下實現Parcelable介面的方法。
通過實現Parcelable介面序列化物件的步驟:
1、實現Parcelable介面。
2、並且實現Parcelable介面的public void writeToParcel(Parcel dest, int flags)方法 。
3、自定義型別中必須含有一個名稱為CREATOR的靜態成員,該成員物件要求實現Parcelable.Creator介面及其方法。
簡而言之:通過writeToParcel將你的物件對映成Parcel物件,再通過createFromParcel將Parcel物件對映成你的物件。
也可以將Parcel看成是一個流,通過writeToParcel把物件寫到流裡面,在通過createFromParcel從流裡讀取物件,只不過這個過程
需要你來實現,因此寫的順序和讀的順序必須一致。
示例程式碼:
package com.yang.domain;
import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable {
//這裡定義了兩個變數來說明讀和寫的順序要一致
private Integer id;
private String name;
public Person() {
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// 把javanbean中的資料寫到Parcel。先寫id然後寫name
dest.writeInt(this.id);
dest.writeString(this.name);
}
// 新增一個靜態成員,名為CREATOR,該物件實現了Parcelable.Creator介面
public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
@Override
public Person createFromParcel(Parcel source) {
// 從Parcel中讀取資料,返回person物件
return new Person(source.readInt(), source.readString());
}
@Override
public Person[] newArray(int size) {
return new Person[size];
}
};
}
要傳遞的資料是由複製資料型別組合而成時:
public class MyParcelable implements Parcelable {
private List<MyListClass> arrList = new ArrayList<MyListClass>();
private int myInt = 0;
private String str = null;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public List<MyListClass> getArrList() {
return arrList;
}
public void setArrList(List<MyListClass> arrList) {
this.arrList = arrList;
}
public int getMyInt() {
return myInt;
}
public void setMyInt(int myInt) {
this.myInt = myInt;
}
MyParcelable() {
// initialization
arrList = new ArrayList<MyListClass>();
}
public MyParcelable(Parcel in) {
myInt = in.readInt();
str = in.readString();
in.readTypedList(arrList, MyListClass.CREATOR);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel outParcel, int flags) {
outParcel.writeInt(myInt);
outParcel.writeString(str);
outParcel.writeTypedList(arrList);
}
public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() {
@Override
public MyParcelable createFromParcel(Parcel in) {
return new MyParcelable(in);
}
@Override
public MyParcelable[] newArray(int size) {
return new MyParcelable[size];
}
};
}
當有子類父類情況時:
public abstract class A implements Parcelable {
private int a;
protected A(int a) {
this.a = a;
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(a);
}
protected A(Parcel in) {
a = in.readInt();
}
}
public class B extends A {
private int b;
public B(int a, int b) {
super(a);
this.b = b;
}
public static final Parcelable.Creator<B> CREATOR = new Parcelable.Creator<B>() {
public B createFromParcel(Parcel in) {
return new B(in);
}
public B[] newArray(int size) {
return new B[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeInt(b);
}
private B(Parcel in) {
super(in);
b = in.readInt();
}
}
2、什麼是Serializable介面?
1)一個物件序列化的介面,一個類只有實現了Serializable介面,它的物件才是可序列化的。因此如果要序列化某些類的物件,這些類就必須實現Serializable介面。而實際上,Serializable是一個空介面,沒有什麼具體內容,它的目的只是簡單的標識一個類的物件可以被序列化。
2)如何實現Serializable介面?
很簡單,只要implements Serializable介面就可以了
3)程式碼實現>
package com.jyxp.my.parcelable;
import java.io.Serializable;
public class MySerializable implements Serializable {
private static final long serialVersionUID = 1L;
private Double mDouble;
private Float mFloat;
public MySerializable() {
// TODO Auto-generated constructor stub
}
public Double getmDouble() {
return mDouble;
}
public void setmDouble(Double mDouble) {
this.mDouble = mDouble;
}
public Float getmFloat() {
return mFloat;
}
public void setmFloat(Float mFloat) {
this.mFloat = mFloat;
}
}
3、如何實現傳值
1)基本資料型別,自身可以
2)傳遞Serializable物件時,被傳遞的Serializable物件裡面的自定義成員物件(非API中的Serializable物件)也要實現
Serializable介面,否則會出現Caused by: java.io.NotSerializableException異常。從上面的程式碼可以看出,
在Parcelable物件中是可以傳遞Serializable物件的,但Serializable物件裡面傳遞的時候可不可以有Parcelable?
回答是否定的,一樣會產生java.io.NotSerializableException異常.
3)android api中只能傳遞Parcelable物件的集合,而不能傳遞Serializable物件的集合,也就是隻能傳遞
ArrayList<Bitmap>,卻不能傳遞ArrayList<Designer>。剛剛開始學android的時候,物件都是被封裝成Serializable,
再傳遞,因為Serializable是JAVASE裡面的本地化介面,很熟悉,當時也產生疑問,為什麼會有Parcelable介面,
這兩個有什麼區別?到後來,當Serializable不能滿足要求的時候就明白了,android利用Pacelable對自己的東西進行
封裝,就像Worker中的Bitmap,在read的時候可以不需要設定ClassLoader。
4)也是可以傳遞列舉enum的,把列舉當做類來看就行了。