Step 7.ContentProviderProxy.query 这个函数定义在frameworks/base/core/java/android/content/ContentProviderNative.java文件中:
  1. finalclassContentProviderProxyimplementsIContentProvider{
  2. ......
  3. publicCursorquery(Uriurl,String[]projection,Stringselection,
  4. String[]selectionArgs,StringsortOrder)throwsRemoteException{
  5. //TODOmakeapoolofwindowssowecanreusememorydealers
  6. CursorWindowwindow=newCursorWindow(false/*windowwillbeusedremotely*/);
  7. BulkCursorToCursorAdaptoradaptor=newBulkCursorToCursorAdaptor();
  8. IBulkCursorbulkCursor=bulkQueryInternal(
  9. url,projection,selection,selectionArgs,sortOrder,
  10. adaptor.getObserver(),window,
  11. adaptor);
  12. if(bulkCursor==null){
  13. returnnull;
  14. }
  15. returnadaptor;
  16. }
  17. ......
  18. }
这个函数首先会创建一个CursorWindow对象,前面已经说过,这个CursorWindow对象包含了一块匿名共享内存,它的作用是把这块匿名共享内存通过Binder进程间通信机制传给Content Proivder,好让Content Proivder在里面返回所请求的数据。下面我们就先看看这个CursorWindow对象的创建过程,重点关注它是如何在内部创建匿名共享内存的,然后再回过头来看看它调用bulkQueryInternal函数来做了些什么事情。 CursorWindow类定义在frameworks/base/core/java/android/database/CursorWindow.java文件中,我们来看看它的构造函数的实现:
  1. publicclassCursorWindowextendsSQLiteClosableimplementsParcelable{
  2. ......
  3. privateintnWindow;
  4. ......
  5. publicCursorWindow(booleanlocalWindow){
  6. ......
  7. native_init(localWindow);
  8. }
  9. ......
  10. }
它主要调用本地方法native_init来执行初始化的工作,主要就是创建匿名共享内存了,传进来的参数localWindow为false,表示这个匿名共享内存只能通过远程调用来访问,即前面我们所说的,通过Content Proivder返回来的Cursor接口来访问这块匿名共享内存里面的数据。 Step 8. CursorWindow.native_init 这是一个JNI方法,它对应定义在frameworks/base/core/jni/android_database_CursorWindow.cpp文件中的native_init_empty函数:
  1. staticJNINativeMethodsMethods[]=
  2. {
  3. /*name,signature,funcPtr*/
  4. {"native_init","(Z)V",(void*)native_init_empty},
  5. ......
  6. };
函数native_init_empty的定义如下所示:
  1. staticvoidnative_init_empty(JNIEnv*env,jobjectobject,jbooleanlocalOnly)
  2. {
  3. ......
  4. CursorWindow*window;
  5. window=newCursorWindow(MAX_WINDOW_SIZE);
  6. ......
  7. if(!window->initBuffer(localOnly)){
  8. ......
  9. }
  10. ......
  11. SET_WINDOW(env,object,window);
  12. }
这个函数在C++层创建了一个CursorWindow对象,然后通过调用SET_WINDOW宏来把这个C++层的CursorWindow对象与Java层的CursorWindow对象关系起来:
  1. #defineSET_WINDOW(env,object,window)(env->SetIntField(object,gWindowField,(int)window))
这里的gWindowField即定义为Java层的CursorWindow对象中的nWindow成员变量:
  1. staticjfieldIDgWindowField;
  2. ......
  3. intregister_android_database_CursorWindow(JNIEnv*env)
  4. {
  5. jclassclazz;
  6. clazz=env->FindClass("android/database/CursorWindow");
  7. ......
  8. gWindowField=env->GetFieldID(clazz,"nWindow","I");
  9. ......
  10. }
这种用法在Android应用程序框架层中非常普遍。 下面我们重点关注C++层的CursorWindow对象的initBuffer函数的实现。 Step 9.CursorWindow.initBuffer C++层的CursorWindow类定义在frameworks/base/core/jni/CursorWindow.cpp文件中:
  1. boolCursorWindow::initBuffer(boollocalOnly)
  2. {
  3. ......
  4. sp<MemoryHeapBase>heap;
  5. heap=newMemoryHeapBase(mMaxSize,0,"CursorWindow");
  6. if(heap!=NULL){
  7. mMemory=newMemoryBase(heap,0,mMaxSize);
  8. if(mMemory!=NULL){
  9. mData=(uint8_t*)mMemory->pointer();
  10. if(mData){
  11. mHeader=(window_header_t*)mData;
  12. mSize=mMaxSize;
  13. ......
  14. }
  15. }
  16. ......
  17. }else{
  18. ......
  19. }
  20. }
这里我们就可以很清楚地看到,在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文件中:
        
  1. finalclassContentProviderProxyimplementsIContentProvider
  2. {
  3. ......
  4. privateIBulkCursorbulkQueryInternal(
  5. Uriurl,String[]projection,
  6. Stringselection,String[]selectionArgs,StringsortOrder,
  7. IContentObserverobserver,CursorWindowwindow,
  8. BulkCursorToCursorAdaptoradaptor)throwsRemoteException{
  9. Parceldata=Parcel.obtain();
  10. Parcelreply=Parcel.obtain();
  11. data.writeInterfaceToken(IContentProvider.descriptor);
  12. url.writeToParcel(data,0);
  13. intlength=0;
  14. if(projection!=null){
  15. length=projection.length;
  16. }
  17. data.writeInt(length);
  18. for(inti=0;i<length;i++){
  19. data.writeString(projection[i]);
  20. }
  21. data.writeString(selection);
  22. if(selectionArgs!=null){
  23. length=selectionArgs.length;
  24. }else{
  25. length=0;
  26. }
  27. data.writeInt(length);
  28. for(inti=0;i<length;i++){
  29. data.writeString(selectionArgs[i]);
  30. }
  31. data.writeString(sortOrder);
  32. data.writeStrongBinder(observer.asBinder());
  33. window.writeToParcel(data,0);
  34. //Flagforwhetherornotwewantthenumberofrowsinthe
  35. //cursorandthepositionofthe"_id"columnindex(or-1if
  36. //non-existent).Onlytobereturnedifbinder!=null.
  37. finalbooleanwantsCursorMetadata=(adaptor!=null);
  38. data.writeInt(wantsCursorMetadata?1:0);
  39. mRemote.transact(IContentProvider.QUERY_TRANSACTION,data,reply,0);
  40. DatabaseUtils.readExceptionFromParcel(reply);
  41. IBulkCursorbulkCursor=null;
  42. IBinderbulkCursorBinder=reply.readStrongBinder();
  43. if(bulkCursorBinder!=null){
  44. bulkCursor=BulkCursorNative.asInterface(bulkCursorBinder);
  45. if(wantsCursorMetadata){
  46. introwCount=reply.readInt();
  47. intidColumnPosition=reply.readInt();
  48. if(bulkCursor!=null){
  49. adaptor.set(bulkCursor,rowCount,idColumnPosition);
  50. }
  51. }
  52. }
  53. data.recycle();
  54. reply.recycle();
  55. returnbulkCursor;
  56. }
  57. ......
  58. }
这个函数有点长,不过它的逻辑很简单,就是把查询参数都写到一个Parcel对象data中去,然后通过下面Binder进程间通信机制把查询请求传给Content Provider处理:
  1. mRemote.transact(IContentProvider.QUERY_TRANSACTION,data,reply,0);
从这个Binder调用返回以后,就会得到一个IBulkCursor接口,它是一个Binder引用,实际是指向在Content Provider这一侧创建的一个CursorToBulkCursorAdaptor对象,后面我们将会看到。有了这个IBulkCursor接口之后,我们就可以通过Binder进程间调用来访问从Content Provider中查询得到的数据了。这个IBulkCursor接口最终最设置了上面Step 7中创建的BulkCursorToCursorAdaptor对象adaptor中去:
  1. adaptor.set(bulkCursor,rowCount,idColumnPosition);
BulkCursorToCursorAdaptor类实现了Cursor接口,因此,我们可以通过Curosr接口来访问这些查询得到的共享数据。 在前面把查询参数写到Parcel对象data中去的过程中,有两个步骤是比较重要的,分别下面这段执行语句:
  1. window.writeToParcel(data,0);
  2. //Flagforwhetherornotwewantthenumberofrowsinthe
  3. //cursorandthepositionofthe"_id"columnindex(or-1if
  4. //non-existent).Onlytobereturnedifbinder!=null.
  5. finalbooleanwantsCursorMetadata=(adaptor!=null);
  6. data.writeInt(wantsCursorMetadata?1:0);
调用window.writeToParcel是把window对象内部的匿名共享内存块通过Binder进程间通信机制传输给Content Provider来使用;而当传进来的参数adaptor不为null时,就会往data中写入一个整数1,表示让Content Provider把查询得到数据的元信息一起返回来,例如数据的行数、数据行的ID列的索引位置等信息,这个整数值会促使Content Provider把前面说的IBulkCursor接口返回给第三方应用程序之前,真正执行一把数据库查询操作,后面我们将看到这个过程。 现在,我们重点来关注一下CursorWindow类的writeToParcel函数,看看它是如何把它内部的匿名共享内存对象写到数据流data中去的。

更多相关文章

  1. 箭头函数的基础使用
  2. 类和 Json对象
  3. Python技巧匿名函数、回调函数和高阶函数
  4. Android的UI两大基石
  5. Android(安卓)Touch事件
  6. android 一直在最前面的浮动窗口效果
  7. Android(安卓)Json解析工具类
  8. android连接mysql数据库
  9. android 如何判断去电或来电已经接通

随机推荐

  1. Learning about Android(安卓)Graphics S
  2. ionic build android时gradle错误
  3. Android(安卓)Hilt
  4. Translation001——android
  5. Android(安卓)使用自定义View画圆
  6. Android隐藏状态栏、导航栏
  7. Android(安卓)MVC模式你真的明白了吗??
  8. Android的水平进度条和圆形进度条实例
  9. android 控件抖动
  10. Android之Fragment界面布局实例