Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)
生活随笔
收集整理的這篇文章主要介紹了
Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?? ?Step 7.?ContentProviderProxy.query ?? ? ?這個函數(shù)定義在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;?? ????}?? ?? ????......?? }?? ?? ? ? ?這個函數(shù)首先會創(chuàng)建一個CursorWindow對象,前面已經(jīng)說過,這個CursorWindow對象包含了一塊匿名共享內(nèi)存,它的作用是把這塊匿名共享內(nèi)存通過Binder進程間通信機制傳給Content Proivder,好讓Content Proivder在里面返回所請求的數(shù)據(jù)。下面我們就先看看這個CursorWindow對象的創(chuàng)建過程,重點關注它是如何在內(nèi)部創(chuàng)建匿名共享內(nèi)存的,然后再回過頭來看看它調(diào)用bulkQueryInternal函數(shù)來做了些什么事情。 ?? ? ? ?CursorWindow類定義在frameworks/base/core/java/android/database/CursorWindow.java文件中,我們來看看它的構造函數(shù)的實現(xiàn): public?class?CursorWindow?extends?SQLiteClosable?implements?Parcelable?{?? ????......?? ?? ????private?int?nWindow;?? ?? ????......?? ?? ????public?CursorWindow(boolean?localWindow)?{?? ????????......?? ?? ????????native_init(localWindow);?? ????}?? ?? ????......?? }?? ? ?? ? ? ?它主要調(diào)用本地方法native_init來執(zhí)行初始化的工作,主要就是創(chuàng)建匿名共享內(nèi)存了,傳進來的參數(shù)localWindow為false,表示這個匿名共享內(nèi)存只能通過遠程調(diào)用來訪問,即前面我們所說的,通過Content Proivder返回來的Cursor接口來訪問這塊匿名共享內(nèi)存里面的數(shù)據(jù)。 ?? ? ? ?Step 8. CursorWindow.native_init ?? ? ? ?這是一個JNI方法,它對應定義在frameworks/base/core/jni/android_database_CursorWindow.cpp文件中的native_init_empty函數(shù): static?JNINativeMethod?sMethods[]?=?? {?? ?????/*?name,?signature,?funcPtr?*/?? ????{"native_init",?"(Z)V",?(void?*)native_init_empty},?? ????......?? };?? ?? ? ? ? 函數(shù)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);?? }?? ?? ? ? ? 這個函數(shù)在C++層創(chuàng)建了一個CursorWindow對象,然后通過調(diào)用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函數(shù)的實現(xiàn)。 ?? ? ? ?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類的內(nèi)部有一個成員變量mMemory,它的類型是MemoryBase。MemoryBase類為我們封裝了匿名共享內(nèi)存的訪問以及在進程間的傳輸?shù)葐栴},具體可以參考前面一篇文章Android系統(tǒng)匿名共享內(nèi)存(Anonymous Shared Memory)C++調(diào)用接口分析,這里就不再詳述了。 ? ?? ? ? ?通過Step 8和Step 9兩步,用來在第三方應用程序和Content Provider之間傳輸數(shù)據(jù)的媒介就準備好了,我們回到Step 7中,看看系統(tǒng)是如何把這個匿名共享存?zhèn)鬟f給Content Provider使用的。在Step 7中,最后調(diào)用bulkQueryInternal函數(shù)來進一步操作。 ?? ? ? ?Step 10.?ContentProviderProxy.bulkQueryInternal ?? ? ?這個函數(shù)定義在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;??? ????}??? ??? ????......??? }??? ? ? ?這個函數(shù)有點長,不過它的邏輯很簡單,就是把查詢參數(shù)都寫到一個Parcel對象data中去,然后通過下面Binder進程間通信機制把查詢請求傳給Content Provider處理:? mRemote.transact(IContentProvider.QUERY_TRANSACTION,?data,?reply,?0);?? ?? ? ?從這個Binder調(diào)用返回以后,就會得到一個IBulkCursor接口,它是一個Binder引用,實際是指向在Content Provider這一側(cè)創(chuàng)建的一個CursorToBulkCursorAdaptor對象,后面我們將會看到。有了這個IBulkCursor接口之后,我們就可以通過Binder進程間調(diào)用來訪問從Content Provider中查詢得到的數(shù)據(jù)了。這個IBulkCursor接口最終最設置了上面Step 7中創(chuàng)建的BulkCursorToCursorAdaptor對象adaptor中去: adaptor.set(bulkCursor,?rowCount,?idColumnPosition);?? ?? ? ?BulkCursorToCursorAdaptor類實現(xiàn)了Cursor接口,因此,我們可以通過Curosr接口來訪問這些查詢得到的共享數(shù)據(jù)。 ? ? ? 在前面把查詢參數(shù)寫到Parcel對象data中去的過程中,有兩個步驟是比較重要的,分別下面這段執(zhí)行語句: 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);?? ?? ? ?調(diào)用window.writeToParcel是把window對象內(nèi)部的匿名共享內(nèi)存塊通過Binder進程間通信機制傳輸給Content Provider來使用;而當傳進來的參數(shù)adaptor不為null時,就會往data中寫入一個整數(shù)1,表示讓Content Provider把查詢得到數(shù)據(jù)的元信息一起返回來,例如數(shù)據(jù)的行數(shù)、數(shù)據(jù)行的ID列的索引位置等信息,這個整數(shù)值會促使Content Provider把前面說的IBulkCursor接口返回給第三方應用程序之前,真正執(zhí)行一把數(shù)據(jù)庫查詢操作,后面我們將看到這個過程。 ? ? ? 現(xiàn)在,我們重點來關注一下CursorWindow類的writeToParcel函數(shù),看看它是如何把它內(nèi)部的匿名共享內(nèi)存對象寫到數(shù)據(jù)流data中去的。
轉(zhuǎn)載于:https://blog.51cto.com/shyluo/966999
總結(jié)
以上是生活随笔為你收集整理的Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 旧手机不要扔掉 旧的手机不要丢)
- 下一篇: android sina oauth2.