1. 程式人生 > >Android開發當中Parcelable,Serializable介面的使用

Android開發當中Parcelable,Serializable介面的使用

Activity之間傳資料時,為了避免麻煩,往往會將一些值封裝成物件,然後將整個物件傳遞過去。

對於Android來說傳遞複雜型別,主要是將自己的類轉換為基礎的位元組陣列,Activity之間傳遞資料是通過Intent實現的。

Android序列化物件主要有兩種方法,實現Serializable介面、或者實現Parcelable介面。實現Serializable介面是Java SE本身就支援

的,而Parcelable是Android特有的功能,效率比實現Serializable介面高,而且還可以用在程序間通訊(IPC)中。

實現Serializable介面非常簡單,宣告一下就可以了。而實現Parcelable介面稍微複雜一些,但效率更高,推薦用這種方法提高效能。

android 中自定義的物件序列化的問題有兩個選擇一個是Parcelable,另外一個是Serializable。 什麼時候使用序列化?

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