天天看點

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) {

  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;

 public void writeToParcel(Parcel dest, int flags) {

  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];

  }

  public MyParcelable createFromParcel(Parcel source) {

   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)代碼實作>

import java.io.Serializable;

public class MySerializable implements Serializable {

 private static final long serialVersionUID = 1L;

 private Double mDouble;

 private Float mFloat;

 public MySerializable() {

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