編輯:關於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 很多天之前就安裝了visual studio community 201
Android項目:手機安全衛士(16)—— 復雜 ListView淺析 Android項目:手機安全衛士(16)—— 復雜 ListView 1
ImageLoader簡單使用,imageloader如圖是效果圖 &nb
Android中SQLite應用詳解 上次我向大家介紹了SQLite的基本信息和使用過程,相信朋友們對SQLite已經有所了解了,那今天呢,我就和大家分享一下在Andro