日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android应用程序组件Content Provider在应用程序之间共享数据的原理分析(2)

發布時間:2023/12/31 Android 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。