Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)
生活随笔
收集整理的這篇文章主要介紹了
Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?? ?Step 7.?ContentProviderProxy.query ?? ? ?這個函數定義在frameworks/base/core/java/android/content/ContentProviderNative.java文件中: final?class?ContentProviderProxy?implements?IContentProvider?{?? ????......?? ?? ????public?Cursor?query(Uri?url,?String[]?projection,?String?selection,?? ????????????String[]?selectionArgs,?String?sortOrder)?throws?RemoteException?{?? ????????//TODO?make?a?pool?of?windows?so?we?can?reuse?memory?dealers?? ????????CursorWindow?window?=?new?CursorWindow(false?/*?window?will?be?used?remotely?*/);?? ????????BulkCursorToCursorAdaptor?adaptor?=?new?BulkCursorToCursorAdaptor();?? ????????IBulkCursor?bulkCursor?=?bulkQueryInternal(?? ????????????url,?projection,?selection,?selectionArgs,?sortOrder,?? ????????????adaptor.getObserver(),?window,?? ????????????adaptor);?? ????????if?(bulkCursor?==?null)?{?? ????????????return?null;?? ????????}?? ????????return?adaptor;?? ????}?? ?? ????......?? }?? ?? ? ? ?這個函數首先會創建一個CursorWindow對象,前面已經說過,這個CursorWindow對象包含了一塊匿名共享內存,它的作用是把這塊匿名共享內存通過Binder進程間通信機制傳給Content Proivder,好讓Content Proivder在里面返回所請求的數據。下面我們就先看看這個CursorWindow對象的創建過程,重點關注它是如何在內部創建匿名共享內存的,然后再回過頭來看看它調用bulkQueryInternal函數來做了些什么事情。 ?? ? ? ?CursorWindow類定義在frameworks/base/core/java/android/database/CursorWindow.java文件中,我們來看看它的構造函數的實現: public?class?CursorWindow?extends?SQLiteClosable?implements?Parcelable?{?? ????......?? ?? ????private?int?nWindow;?? ?? ????......?? ?? ????public?CursorWindow(boolean?localWindow)?{?? ????????......?? ?? ????????native_init(localWindow);?? ????}?? ?? ????......?? }?? ? ?? ? ? ?它主要調用本地方法native_init來執行初始化的工作,主要就是創建匿名共享內存了,傳進來的參數localWindow為false,表示這個匿名共享內存只能通過遠程調用來訪問,即前面我們所說的,通過Content Proivder返回來的Cursor接口來訪問這塊匿名共享內存里面的數據。 ?? ? ? ?Step 8. CursorWindow.native_init ?? ? ? ?這是一個JNI方法,它對應定義在frameworks/base/core/jni/android_database_CursorWindow.cpp文件中的native_init_empty函數: static?JNINativeMethod?sMethods[]?=?? {?? ?????/*?name,?signature,?funcPtr?*/?? ????{"native_init",?"(Z)V",?(void?*)native_init_empty},?? ????......?? };?? ?? ? ? ? 函數native_init_empty的定義如下所示: static?void?native_init_empty(JNIEnv?*?env,?jobject?object,?jboolean?localOnly)?? {?? ????......?? ?? ????CursorWindow?*?window;?? ?? ????window?=?new?CursorWindow(MAX_WINDOW_SIZE);?? ????......?? ?? ????if?(!window->initBuffer(localOnly))?{?? ????????......?? ????}?? ?? ????......?? ????SET_WINDOW(env,?object,?window);?? }?? ?? ? ? ? 這個函數在C++層創建了一個CursorWindow對象,然后通過調用SET_WINDOW宏來把這個C++層的CursorWindow對象與Java層的CursorWindow對象關系起來: #define?SET_WINDOW(env,?object,?window)?(env->SetIntField(object,?gWindowField,?(int)window))?? ?? ? ? ? 這里的gWindowField即定義為Java層的CursorWindow對象中的nWindow成員變量: static?jfieldID?gWindowField;?? ?? ......?? ?? int?register_android_database_CursorWindow(JNIEnv?*?env)?? {?? ????jclass?clazz;?? ?? ????clazz?=?env->FindClass("android/database/CursorWindow");?? ????......?? ?? ????gWindowField?=?env->GetFieldID(clazz,?"nWindow",?"I");?? ?? ????......?? }?? ?? ? ? ?這種用法在Android應用程序框架層中非常普遍。 ? ?? ? ? ?下面我們重點關注C++層的CursorWindow對象的initBuffer函數的實現。 ?? ? ? ?Step 9.?CursorWindow.initBuffer ?? ? ? ?C++層的CursorWindow類定義在frameworks/base/core/jni/CursorWindow.cpp文件中: bool?CursorWindow::initBuffer(bool?localOnly)?? {?? ????......?? ?? ????sp<MemoryHeapBase>?heap;?? ????heap?=?new?MemoryHeapBase(mMaxSize,?0,?"CursorWindow");?? ????if?(heap?!=?NULL)?{?? ????????mMemory?=?new?MemoryBase(heap,?0,?mMaxSize);?? ????????if?(mMemory?!=?NULL)?{?? ????????????mData?=?(uint8_t?*)?mMemory->pointer();?? ????????????if?(mData)?{?? ????????????????mHeader?=?(window_header_t?*)?mData;?? ????????????????mSize?=?mMaxSize;?? ?? ????????????????......?? ????????????}?? ????????}?? ????????......?? ????}?else?{?? ????????......?? ????}?? }?? ?? ? ? ?這里我們就可以很清楚地看到,在CursorWindow類的內部有一個成員變量mMemory,它的類型是MemoryBase。MemoryBase類為我們封裝了匿名共享內存的訪問以及在進程間的傳輸等問題,具體可以參考前面一篇文章Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析,這里就不再詳述了。 ? ?? ? ? ?通過Step 8和Step 9兩步,用來在第三方應用程序和Content Provider之間傳輸數據的媒介就準備好了,我們回到Step 7中,看看系統是如何把這個匿名共享存傳遞給Content Provider使用的。在Step 7中,最后調用bulkQueryInternal函數來進一步操作。 ?? ? ? ?Step 10.?ContentProviderProxy.bulkQueryInternal ?? ? ?這個函數定義在frameworks/base/core/java/android/content/ContentProviderNative.java文件中: final?class?ContentProviderProxy?implements?IContentProvider??? {??? ????......??? ??? ????private?IBulkCursor?bulkQueryInternal(??? ????????????Uri?url,?String[]?projection,??? ????????????String?selection,?String[]?selectionArgs,?String?sortOrder,??? ????????????IContentObserver?observer,?CursorWindow?window,??? ????????????BulkCursorToCursorAdaptor?adaptor)?throws?RemoteException?{??? ????????Parcel?data?=?Parcel.obtain();??? ????????Parcel?reply?=?Parcel.obtain();??? ??? ????????data.writeInterfaceToken(IContentProvider.descriptor);??? ??? ????????url.writeToParcel(data,?0);??? ????????int?length?=?0;??? ????????if?(projection?!=?null)?{??? ????????????length?=?projection.length;??? ????????}??? ????????data.writeInt(length);??? ????????for?(int?i?=?0;?i?<?length;?i++)?{??? ????????????data.writeString(projection[i]);??? ????????}??? ????????data.writeString(selection);??? ????????if?(selectionArgs?!=?null)?{??? ????????????length?=?selectionArgs.length;??? ????????}?else?{??? ????????????length?=?0;??? ????????}??? ????????data.writeInt(length);??? ????????for?(int?i?=?0;?i?<?length;?i++)?{??? ????????????data.writeString(selectionArgs[i]);??? ????????}??? ????????data.writeString(sortOrder);??? ????????data.writeStrongBinder(observer.asBinder());??? ????????window.writeToParcel(data,?0);??? ??? ????????//?Flag?for?whether?or?not?we?want?the?number?of?rows?in?the??? ????????//?cursor?and?the?position?of?the?"_id"?column?index?(or?-1?if??? ????????//?non-existent).??Only?to?be?returned?if?binder?!=?null.??? ????????final?boolean?wantsCursorMetadata?=?(adaptor?!=?null);??? ????????data.writeInt(wantsCursorMetadata???1?:?0);??? ??? ????????mRemote.transact(IContentProvider.QUERY_TRANSACTION,?data,?reply,?0);??? ??? ????????DatabaseUtils.readExceptionFromParcel(reply);??? ??? ????????IBulkCursor?bulkCursor?=?null;??? ????????IBinder?bulkCursorBinder?=?reply.readStrongBinder();??? ????????if?(bulkCursorBinder?!=?null)?{??? ????????????bulkCursor?=?BulkCursorNative.asInterface(bulkCursorBinder);??? ??? ????????????if?(wantsCursorMetadata)?{??? ????????????????int?rowCount?=?reply.readInt();??? ????????????????int?idColumnPosition?=?reply.readInt();??? ????????????????if?(bulkCursor?!=?null)?{??? ????????????????????adaptor.set(bulkCursor,?rowCount,?idColumnPosition);??? ????????????????}??? ????????????}??? ????????}??? ??? ????????data.recycle();??? ????????reply.recycle();??? ??? ????????return?bulkCursor;??? ????}??? ??? ????......??? }??? ? ? ?這個函數有點長,不過它的邏輯很簡單,就是把查詢參數都寫到一個Parcel對象data中去,然后通過下面Binder進程間通信機制把查詢請求傳給Content Provider處理:? mRemote.transact(IContentProvider.QUERY_TRANSACTION,?data,?reply,?0);?? ?? ? ?從這個Binder調用返回以后,就會得到一個IBulkCursor接口,它是一個Binder引用,實際是指向在Content Provider這一側創建的一個CursorToBulkCursorAdaptor對象,后面我們將會看到。有了這個IBulkCursor接口之后,我們就可以通過Binder進程間調用來訪問從Content Provider中查詢得到的數據了。這個IBulkCursor接口最終最設置了上面Step 7中創建的BulkCursorToCursorAdaptor對象adaptor中去: adaptor.set(bulkCursor,?rowCount,?idColumnPosition);?? ?? ? ?BulkCursorToCursorAdaptor類實現了Cursor接口,因此,我們可以通過Curosr接口來訪問這些查詢得到的共享數據。 ? ? ? 在前面把查詢參數寫到Parcel對象data中去的過程中,有兩個步驟是比較重要的,分別下面這段執行語句: window.writeToParcel(data,?0);?? ?? //?Flag?for?whether?or?not?we?want?the?number?of?rows?in?the?? //?cursor?and?the?position?of?the?"_id"?column?index?(or?-1?if?? //?non-existent).??Only?to?be?returned?if?binder?!=?null.?? final?boolean?wantsCursorMetadata?=?(adaptor?!=?null);?? data.writeInt(wantsCursorMetadata???1?:?0);?? ?? ? ?調用window.writeToParcel是把window對象內部的匿名共享內存塊通過Binder進程間通信機制傳輸給Content Provider來使用;而當傳進來的參數adaptor不為null時,就會往data中寫入一個整數1,表示讓Content Provider把查詢得到數據的元信息一起返回來,例如數據的行數、數據行的ID列的索引位置等信息,這個整數值會促使Content Provider把前面說的IBulkCursor接口返回給第三方應用程序之前,真正執行一把數據庫查詢操作,后面我們將看到這個過程。 ? ? ? 現在,我們重點來關注一下CursorWindow類的writeToParcel函數,看看它是如何把它內部的匿名共享內存對象寫到數據流data中去的。
轉載于:https://blog.51cto.com/shyluo/966999
總結
以上是生活随笔為你收集整理的Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 旧手机不要扔掉 旧的手机不要丢)
- 下一篇: “提着你去看精彩视界”——酷乐视R4S全