1. 程式人生 > >android Activity之間資料傳遞 Parcelable和Serializable介面的使用

android Activity之間資料傳遞 Parcelable和Serializable介面的使用

Activity之間傳資料時,為了避免麻煩,往往會將一些值封裝成物件,然後將整個物件傳遞過去。傳物件的時候有兩種情況,一種是實現Parcelable介面,一種是實現Serializable介面。

0、解釋兩種介面:

1)實現Serializable介面是JavaSE本身就支援的。

2)Parcelable是Android特有的功能,效率比實現Serializable介面高,像用於Intent資料傳遞也都支援,而且還可以用在程序間通訊(IPC),除了基本型別外,只有實現了Parcelable介面的類才能被放入Parcel中。

3)什麼時候使用序列化?

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的類的例項處理。因為實現類在這裡還是不可知的,所以需要用到模板的方式,繼承類名通過模板引數傳入。
    //為了能夠實現模板引數的傳入,這裡定義Creator嵌入介面,內含兩個介面函式分別返回單個和多個繼承類例項。
    public interface Creator<T> {
        public T createFromParcel(Parcel source);
        public T[] newArray(int size);
	}
}
3)怎麼實現Parcelable介面?

從parcelable介面定義中,我們可以看到,實現parcelable介面,需要我們實現下面幾個方法:

(1.)describeContents方法。內容介面描述,預設返回0就可以;

(2.)writeToParcel 方法。該方法將類的資料寫入外部提供的Parcel中.即打包需要傳遞的資料到Parcel容器儲存,以便從parcel容器獲取資料,該方法宣告如下:

writeToParcel (Parcel dest, int flags) 具體引數含義見doc文件

(3.)靜態的Parcelable.Creator介面,本介面有兩個方法:

createFromParcel(Parcel in)  從Parcel容器中讀取傳遞資料值,封裝成Parcelable物件返回邏輯層

newArray(int size) 建立一個型別為T,長度為size的陣列,僅一句話(return new T[size])即可。方法是供外部類反序列化本類陣列使用

4)程式碼實現>

(1.)實現MyParcelable類:

package com.jyxp.my.parcelable;

import java.util.ArrayList;
import java.util.List;

import android.os.Parcel;
import android.os.Parcelable;

public class MyParcelable implements Parcelable {
	
	private int mInteger;
	private MyParcelable2 mParcelable;
	private List<MyParcelable2> myParcelable2s = new ArrayList<MyParcelable2>();
	private MySerializable mMySerializable;
	
	public MyParcelable() {
		// TODO Auto-generated constructor stub
	}
	
	@SuppressWarnings("unchecked")
	public MyParcelable(Parcel in) {
		// TODO Auto-generated constructor stub
		mInteger = in.readInt();
		mParcelable = in.readParcelable(MyParcelable2.class.getClassLoader());	//這個地方的ClassLoader不能為null
		myParcelable2s = in.readArrayList(MyParcelable2.class.getClassLoader());
		mMySerializable = (MySerializable) in.readSerializable();
	}

	public int getmInteger() {
		return mInteger;
	}

	public void setmInteger(int mInteger) {
		this.mInteger = mInteger;
	}

	public MyParcelable2 getmParcelable() {
		return mParcelable;
	}

	public void setmParcelable(MyParcelable2 mParcelable) {
		this.mParcelable = mParcelable;
	}

	public List<MyParcelable2> getMyParcelable2s() {
		return myParcelable2s;
	}

	public void setMyParcelable2s(List<MyParcelable2> myParcelable2s) {
		this.myParcelable2s = myParcelable2s;
	}

	public MySerializable getmMySerializable() {
		return mMySerializable;
	}

	public void setmMySerializable(MySerializable mMySerializable) {
		this.mMySerializable = mMySerializable;
	}

	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		// TODO Auto-generated method stub
		dest.writeInt(mInteger);
		dest.writeParcelable(mParcelable, flags);
		dest.writeList(myParcelable2s);
		dest.writeSerializable(mMySerializable);		
	}
    
	public static final Parcelable.Creator<MyParcelable> CREATOR = new Creator<MyParcelable>() {
		
		@Override
		public MyParcelable[] newArray(int size) {
			// TODO Auto-generated method stub
			return new MyParcelable[size];
		}
		
		@Override
		public MyParcelable createFromParcel(Parcel source) {
			// TODO Auto-generated method stub
			return new MyParcelable(source);
		}
	};
}
注意:

1、必須實現Parcelable.Creator介面,並且訪問控制必須是public!!;實現Parcelable.Creator介面物件名必須為CREATOR!!否則在獲取資料的時候,會報錯,如下:android.os.BadParcelableException:

2、在讀取Parcel容器裡的資料時,必須按成員變數宣告的順序讀取資料,不然會出現獲取資料出錯。

3、注意Parcel out和in對應的屬性順序不能錯,否則得不到值;如果想傳遞的值沒有write和read,同樣也是獲取不到值的。

4、實現Parcelable介面我採用的做法是,從android API文件中找到Parcelable介面,詳見Android 文件,將demo copy,然後將MyParcelable類名全部替換,再填寫write和read的值。在填寫值的時候上面的程式碼給出了一些示例,有時候會出現以下錯誤:

(1、)Caused By:android.os.BadParcelableException: ClassNotFoundException when unmarshalling,原因是ClassLoader設定不對,或者沒有傳入ClassLoader

(2、)java.lang.RuntimeException: Parcelable encountered IOException writing serializable object,原因是傳遞的Parcelable物件裡面的物件也要Parcelable或者Serializable。

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的,把列舉當做類來看就行了。

5)short、char、CharSequence、Map、List是不支援的,建議換成int、String、String、HashMap、ArrayList。

6)Android Studio建議安裝Android Parcelable code generation Plugin,直接ALT+INSERT找Parcelable就可以了。

4、例項程式碼>

轉載請註明出處:http://blog.csdn.net/js931178805/article/details/8268144謝謝