編輯:關於android開發
我們已經知道在Android使用Intent/Bindler進行IPC傳輸數據時,需要將對象進行序列化。
JAVA原本已經提供了Serializable接口來實現序列化,使用起來非常簡單,主要用於對象持久化以及對象的網絡傳輸。Serializable開銷比較大,因為序列化和反序列化的過程需要大量的I/O操作。
Android提供了Parcelable對象序列化操作是內存序列化,主要用於Intent/Bindler的IPC數據傳輸。
比如我們使用Parcelable在兩個activity直接通過intent進行傳輸一個Book的對象。
1 package org.xerrard.demo2;
2
3 import android.os.Parcel;
4 import android.os.Parcelable;
5
6 /**
7 * Created by xuqiang on 16-1-20.
8 */
9 public class Book implements Parcelable{
10
11 public String bookname;
12
13 public Book(String bookname){
14 this.bookname = bookname;
15 }
16
17 protected Book(Parcel in) {
18 bookname = in.readString();
19 }
20
21 public static final Creator<Book> CREATOR = new Creator<Book>() {
22 @Override
23 public Book createFromParcel(Parcel in) {
24 return new Book(in);
25 }
26
27 @Override
28 public Book[] newArray(int size) {
29 return new Book[size];
30 }
31 };
32
33 @Override
34 public int describeContents() {
35 return 0;
36 }
37
38 @Override
39 public void writeToParcel(Parcel dest, int flags) {
40 dest.writeInt(bookname);
41 }
42 }
我們需要完成以下幾部。
1. 實現Parcelable接口
2. 添加實體屬性
3. 覆寫writeToParcel(Parcel dest, int flags)方法,指定寫入Parcel類的數據。
4. 創建Parcelable.Creator靜態對象,有兩個方法createFromParcel(Parcel in)與newArray(int size),前者指定如何從Parcel中讀取出數據對象,後者創建一個數組。
5. 覆寫describeContents方法,默認返回0。
然後我們就可以使用Intent中的putExtra方法將Book對象寫入Intent中,然後使用getExtra方法,就可以從Intent中讀出Book對象。
從上面的例子可以看到,Parcelable的序列化方式使用起來還是比較麻煩的。但是,這種方式效率上是比較好的,因為Parcelable的序列化過程是再底層native通過內存操作實現的。
詳細的JNI和C/C++底層的內存操作可以看這篇文章探索Android中的Parcel機制(上)
摘抄裡面最重要的一句結論
整個讀寫全是在內存中進行,主要是通過malloc()、realloc()、memcpy()等內存操作進行,所以效率比JAVA序列化中使用外部存儲器會高很多
因此,在IPC過程中,android推薦使用Parcelable序列化方式
我們知道如果要使用Parcelable,必須按照要求實現這五項操作
1. 實現Parcelable接口
2. 添加實體屬性
3. 覆寫writeToParcel(Parcel dest, int flags)方法,指定寫入Parcel類的數據。
4. 創建Parcelable.Creator靜態對象,有兩個方法createFromParcel(Parcel in)與newArray(int size),前者指定如何從Parcel中讀取出數據對象,後者創建一個數組。
5. 覆寫describeContents方法,默認返回0。
這裡面又是怎樣的調用關系呢?

我們看到,writeToParcel是在startActivity的過程中由intent->Bundle->Parcel 一步一步的調用的,然後WriteToParcel會調用native方法,在底層做序列化操作

而createFromParcel是在收到Intent之後,由Intent->Bundle->Parcel 一步一步的調用。
由此可以看出,Parcel的填包解包都是離不開Bundle的。
這裡其實還是有一個疑問,這個Creator是怎麼一回事呢?
我們從源碼中截取Creator這部分來看看。
1 public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
2 Parcelable.Creator<T> creator = readParcelableCreator(loader);
3 if (creator == null) {
4 return null;
5 }
6 if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
7 return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
8 }
9 return creator.createFromParcel(this);
10 }
11
12 /** @hide */
13 public final <T extends Parcelable> T readCreator(Parcelable.Creator<T> creator,
14 ClassLoader loader) {
15 if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
16 return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
17 }
18 return creator.createFromParcel(this);
19 }
20
21 /** @hide */
22 public final <T extends Parcelable> Parcelable.Creator<T> readParcelableCreator(
23 ClassLoader loader) {
24 String name = readString(); //此處獲得類名,還不太清楚如何獲得的,如果想深入學習可以再研究
25 if (name == null) {
26 return null;
27 }
28 Parcelable.Creator<T> creator;
29 synchronized (mCreators) {
30 HashMap<String,Parcelable.Creator> map = mCreators.get(loader);
31 if (map == null) {
32 map = new HashMap<String,Parcelable.Creator>();
33 mCreators.put(loader, map);
34 }
35 creator = map.get(name);
36 if (creator == null) {
37 try {
38 Class c = loader == null ?
39 Class.forName(name) : Class.forName(name, true, loader);
40 Field f = c.getField("CREATOR");
41 creator = (Parcelable.Creator)f.get(null);
42 }
43 catch (IllegalAccessException e) {
44 Log.e(TAG, "Illegal access when unmarshalling: "
45 + name, e);
46 throw new BadParcelableException(
47 "IllegalAccessException when unmarshalling: " + name);
48 }
49 catch (ClassNotFoundException e) {
50 Log.e(TAG, "Class not found when unmarshalling: "
51 + name, e);
52 throw new BadParcelableException(
53 "ClassNotFoundException when unmarshalling: " + name);
54 }
55 catch (ClassCastException e) {
56 throw new BadParcelableException("Parcelable protocol requires a "
57 + "Parcelable.Creator object called "
58 + " CREATOR on class " + name);
59 }
60 catch (NoSuchFieldException e) {
61 throw new BadParcelableException("Parcelable protocol requires a "
62 + "Parcelable.Creator object called "
63 + " CREATOR on class " + name);
64 }
65 catch (NullPointerException e) {
66 throw new BadParcelableException("Parcelable protocol requires "
67 + "the CREATOR object to be static on class " + name);
68 }
69 if (creator == null) {
70 throw new BadParcelableException("Parcelable protocol requires a "
71 + "Parcelable.Creator object called "
72 + " CREATOR on class " + name);
73 }
74
75 map.put(name, creator);
76 }
77 }
78
79 return creator;
80 }
重點看粗體部分的代碼——真想大白:
在接收端收到parcel之後,解析的時候,會通過反射去獲取對象的Creator,然後保存到一個hashmap中。然後調用Creator的createFromParcel方法來實現解包。
反射在源碼中也是無處不在!
Apache Cordova開發Android應用程序——番外篇,cordovaandroid
Apache Cordova開發Android應用程序——番外篇,cordovaandroid 很多天之前就安裝了visual studio community 201
Android項目:手機安全衛士(16)—— 復雜 ListView淺析
Android項目:手機安全衛士(16)—— 復雜 ListView淺析 Android項目:手機安全衛士(16)—— 復雜 ListView 1
ImageLoader簡單使用,imageloader
ImageLoader簡單使用,imageloader如圖是效果圖 &nb
Android中SQLite應用詳解
Android中SQLite應用詳解 上次我向大家介紹了SQLite的基本信息和使用過程,相信朋友們對SQLite已經有所了解了,那今天呢,我就和大家分享一下在Andro