Step 16. CursorWindow.native_init 这个函数定义在frameworks/base/core/jni/android_database_CursorWindow.cpp文件中,对应的函数为native_init_memory函数:
  1. staticJNINativeMethodsMethods[]=
  2. {
  3. ......
  4. {"native_init","(Landroid/os/IBinder;)V",(void*)native_init_memory},
  5. };
函数native_init_memory的实现如下所示:
  1. staticvoidnative_init_memory(JNIEnv*env,jobjectobject,jobjectmemObj)
  2. {
  3. sp<IMemory>memory=interface_cast<IMemory>(ibinderForJavaObject(env,memObj));
  4. ......
  5. CursorWindow*window=newCursorWindow();
  6. ......
  7. if(!window->setMemory(memory)){
  8. ......
  9. }
  10. ......
  11. SET_WINDOW(env,object,window);
  12. }
函数首先是将前面Step 15中传进来的Binder接口转换为IMemory接口,接着创建一个C++层的CursorWindow对象,再接着用这个IMemory接口来初始化这个C++层的CursorWindow对象,最后像前面的Step 8一样,通过宏SET_WINDOW把这个C++层的CursorWindow对象和前面在Step 15中创建的Java层CursorWindow对象关联起来。 下面我们就重点关注CursorWindow类的setMemory函数的实现,看看它是如何使用这个IMemory接口来初始化其内部的匿名共享内存对象的。 Step 17. CursorWindow.setMemory 这个函数定义在frameworks/base/core/jni/CursorWindow.cpp文件中:
  1. boolCursorWindow::setMemory(constsp<IMemory>&memory)
  2. {
  3. mMemory=memory;
  4. mData=(uint8_t*)memory->pointer();
  5. ......
  6. mHeader=(window_header_t*)mData;
  7. //Makethewindowread-only
  8. ssize_tsize=memory->size();
  9. mSize=size;
  10. mMaxSize=size;
  11. mFreeOffset=size;
  12. ......
  13. returntrue;
  14. }
从前面一篇文章 Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析中,我们知道,这里得到的IMemory接口,实际上是一个Binder引用,它指向前面在Step 9中创建的MemoryBase对象,当我们第一次调用这个接口的pointer函数时,它便会通过Binder进程间通信机制去请求这个MemoryBase对象把它内部的匿名共享内存文件描述符返回来给它,而Binder驱动程序发现要传输的是一个文件描述符的时候,就会在目标进程中创建另外一个文件描述符,这个新建的文件描述符与要传输的文件描述符指向的是同一个文件,在我们这个情景中,这个文件就是我们前面创建的匿名共享内存文件了。因此,在目标进程中,即在Content Provider进程中,它可以通过这个新建的文件描述符来访问这块匿名共享内存,这也是匿名共享内存在进程间的共享原理,具体可以参考另外一篇文章Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析 这样,在Content Provider这一侧,就可以把第三方应用程序请求的数据保存在这个匿名共享内存中了,回到前面的Step 14中,下一步要执行的函数便是bulkQuery了,它的作用为请求的数据制定好一个SQL数据库查询计划。这个bulkQuery函数是由一个实现了IContentProvider接口的Binder对象来实现的,具体可以参考前面一篇文章 Android应用程序组件Content Provider的启动过程源代码分析 中,这个Binder对象的实际类型是定义在ContentProivder类内部的Transport类。 Step 18. Transport.bulkQuery 这个函数定义在frameworks/base/core/java/android/content/ContentProvider.java文件中:
  1. publicabstractclassContentProviderimplementsComponentCallbacks{
  2. ......
  3. classTransportextendsContentProviderNative{
  4. ......
  5. publicIBulkCursorbulkQuery(Uriuri,String[]projection,
  6. Stringselection,String[]selectionArgs,StringsortOrder,
  7. IContentObserverobserver,CursorWindowwindow){
  8. ......
  9. Cursorcursor=ContentProvider.this.query(uri,projection,
  10. selection,selectionArgs,sortOrder);
  11. ......
  12. returnnewCursorToBulkCursorAdaptor(cursor,observer,
  13. ContentProvider.this.getClass().getName(),
  14. hasWritePermission(uri),window);
  15. }
  16. ......
  17. }
  18. ......
  19. }
这个函数主要做了两件事情,一是调用ContentProvider的子类的query函数构造一个数据库查询计划,注意,从这个函数返回来的时候,还没有真正执行数据库查询的操作,而只是按照查询条件准备好了一个SQL语句,要等到第一次使用的时候才会去执行数据库查询操作;二是使用前面一步得到的Cursor接口以及传下来的参数window来创建一个CursorToBulkCursorAdaptor对象,这个对象实现了IBulkCursor接口,同时它也是一个Binder对象,是用来返回给第三方应用程序使用的,第三方应用程序必须通过这个接口来获取从ContentProvider中查询得到的数据,而这个CursorToBulkCursorAdaptor对象的功能就是利用前面获得的Cursor接口来执行数据库查询操作,然后把查询得到的结果保存在从参数传下来的window对象内部所引用的匿名共享内存中去。我们先来看ContentProvider的子类的query函数的实现,在我们这个情景中,这个子类就是ArticlesProvider了,然后再回过头来看看这个CursorToBulkCursorAdaptor对象是如何把数据库查询计划与匿名共享内存关联起来的。 Step 19. ArticlesProvider.query 这个函数定义在前面一篇文章 Android应用程序组件Content Provider应用实例 介绍的应用程序ArtilcesProvider源代码工程目录下,在文件packages/experimental/ArticlesProvider/src/shy/luo/providers/articles/ArticlesProvider.java中:
  1. publicclassArticlesProviderextendsContentProvider{
  2. ......
  3. @Override
  4. publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder){
  5. SQLiteDatabasedb=dbHelper.getReadableDatabase();
  6. SQLiteQueryBuildersqlBuilder=newSQLiteQueryBuilder();
  7. Stringlimit=null;
  8. switch(uriMatcher.match(uri)){
  9. ......
  10. caseArticles.ITEM_POS:{
  11. Stringpos=uri.getPathSegments().get(1);
  12. sqlBuilder.setTables(DB_TABLE);
  13. sqlBuilder.setProjectionMap(articleProjectionMap);
  14. limit=pos+",1";
  15. break;
  16. }
  17. ......
  18. }
  19. Cursorcursor=sqlBuilder.query(db,projection,selection,selectionArgs,null,null,TextUtils.isEmpty(sortOrder)?Articles.DEFAULT_SORT_ORDER:sortOrder,limit);
  20. ......
  21. returncursor;
  22. }
  23. ......
  24. }
从前面的Step 1中可以看到,传进来的参数uri的值为“content://shy.luo.providers.articles/pos”,通过uriMatcher的match函数来匹配这个uri的时候,得到的匹配码为Articles.ITEM_POS,这个知识点可以参考前面这篇文章 Android应用程序组件Content Provider应用实例 。因为我们的数据是保存在SQLite数据库里面的,因此,必须要构造一个SQL语句来将所请求的数据查询出来。这里是通过SQLiteQueryBuilder类来构造这个SQL查询语句的,构造好了以后,就调用它的query函数来准备一个数据库查询计划。Step 20.SQLiteQueryBuilder.query 这个函数定义在frameworks/base/core/java/android/database/sqlite/SQLiteQueryBuilder.java文件中:
  1. publicclassSQLiteQueryBuilder
  2. {
  3. ......
  4. publicCursorquery(SQLiteDatabasedb,String[]projectionIn,
  5. Stringselection,String[]selectionArgs,StringgroupBy,
  6. Stringhaving,StringsortOrder,Stringlimit){
  7. ......
  8. Stringsql=buildQuery(
  9. projectionIn,selection,groupBy,having,
  10. sortOrder,limit);
  11. ......
  12. returndb.rawQueryWithFactory(
  13. mFactory,sql,selectionArgs,
  14. SQLiteDatabase.findEditTable(mTables));
  15. }
  16. ......
  17. }
这里首先是调用buildQuery函数来构造一个SQL语句,它无非就是根据从参数传来列名子句、select子句、where子句、group by子句、having子句、order子句以及limit子句来构造一个完整的SQL子句,这些都是SQL语法的基础知识了,这里我们就不关注了。构造好这个SQL查询语句之后,就调用从参数传下来的数据库对象db的rawQueryWithFactory函数来进一步操作了。 Step 21. SQLiteDatabase.rawQueryWithFactory 这个函数定义在frameworks/base/core/java/android/database/sqlite/SQLiteDatabase.java文件中:
  1. publicclassSQLiteDatabaseextendsSQLiteClosable{
  2. ......
  3. publicCursorrawQueryWithFactory(
  4. CursorFactorycursorFactory,Stringsql,String[]selectionArgs,
  5. StringeditTable){
  6. ......
  7. SQLiteCursorDriverdriver=newSQLiteDirectCursorDriver(this,sql,editTable);
  8. Cursorcursor=null;
  9. try{
  10. cursor=driver.query(
  11. cursorFactory!=null?cursorFactory:mFactory,
  12. selectionArgs);
  13. }finally{
  14. ......
  15. }
  16. returncursor;
  17. }
  18. ......
  19. }
这个函数会在内部创建一个SQLiteCursorDriver对象driver,然后调用它的query函数来创建一个Cursor对象,这个Cursor对象的实际类型是SQLiteCursor,下面我们将会看到,前面我们也已经看到,这个SQLiteCursor的内部就包含了一个数据库查询计划。

更多相关文章

  1. C语言函数的递归(上)
  2. android实时监听网络状态并在断网的情况下打开网络设置
  3. Android中的几种网络请求方式
  4. Android多媒体学习六:利用Service实现背景音乐的播放
  5. Android(安卓)执行 FFmpeg 命令
  6. Android(安卓)Handler removeMessages引发postDelayed失效的问题
  7. android loader用法
  8. Logger详解(二)
  9. Android(安卓)HTTP通讯

随机推荐

  1. Android中导入的java包详解
  2. Android(安卓)提示版本更新的实现
  3. Flutter多平台适配机制就是这么简单
  4. Android(安卓)SO文件的概念、兼容、适配
  5. android: 接收和发送短信
  6. Bitmaps加载之内存管理
  7. Android(安卓)组件系列-----Activity保存
  8. Android(安卓)SqliteManager 源码
  9. Activity 生命周期(一)
  10. 【资源介绍】iGou Android(安卓)开发视频