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

简介:
  Step 16. CursorWindow.native_init
      这个函数定义在frameworks/base/core/jni/android_database_CursorWindow.cpp文件中,对应的函数为native_init_memory函数:
  1. static JNINativeMethod sMethods[] =  
  2. {  
  3.     ......  
  4.     {"native_init""(Landroid/os/IBinder;)V", (void *)native_init_memory},  
  5. };  
      函数native_init_memory的实现如下所示:
  1. static void native_init_memory(JNIEnv * env, jobject object, jobject memObj)  
  2. {  
  3.     sp<IMemory> memory = interface_cast<IMemory>(ibinderForJavaObject(env, memObj));  
  4.     ......  
  5.   
  6.     CursorWindow * window = new CursorWindow();  
  7.     ......  
  8.     if (!window->setMemory(memory)) {  
  9.        ......  
  10.     }  
  11.   
  12.     ......  
  13.     SET_WINDOW(env, object, window);  
  14. }  
      函数首先是将前面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. bool CursorWindow::setMemory(const sp<IMemory>& memory)  
  2. {  
  3.     mMemory = memory;  
  4.     mData = (uint8_t *) memory->pointer();  
  5.     ......  
  6.     mHeader = (window_header_t *) mData;  
  7.   
  8.     // Make the window read-only  
  9.     ssize_t size = memory->size();  
  10.     mSize = size;  
  11.     mMaxSize = size;  
  12.     mFreeOffset = size;  
  13.     ......  
  14.     return true;  
  15. }  
      从前面一篇文章 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. public abstract class ContentProvider implements ComponentCallbacks {  
  2.     ......  
  3.   
  4.     class Transport extends ContentProviderNative {  
  5.         ......  
  6.   
  7.         public IBulkCursor bulkQuery(Uri uri, String[] projection,  
  8.                 String selection, String[] selectionArgs, String sortOrder,  
  9.                 IContentObserver observer, CursorWindow window) {  
  10.             ......  
  11.   
  12.             Cursor cursor = ContentProvider.this.query(uri, projection,  
  13.                 selection, selectionArgs, sortOrder);  
  14.             ......  
  15.   
  16.             return new CursorToBulkCursorAdaptor(cursor, observer,  
  17.                 ContentProvider.this.getClass().getName(),  
  18.                 hasWritePermission(uri), window);  
  19.         }  
  20.   
  21.         ......  
  22.     }  
  23.   
  24.     ......  
  25. }  
        这个函数主要做了两件事情,一是调用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. public class ArticlesProvider extends ContentProvider {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {  
  6.         SQLiteDatabase db = dbHelper.getReadableDatabase();  
  7.   
  8.         SQLiteQueryBuilder sqlBuilder = new SQLiteQueryBuilder();  
  9.         String limit = null;  
  10.   
  11.         switch (uriMatcher.match(uri)) {  
  12.             ......  
  13.             case Articles.ITEM_POS: {  
  14.                 String pos = uri.getPathSegments().get(1);  
  15.                 sqlBuilder.setTables(DB_TABLE);  
  16.                 sqlBuilder.setProjectionMap(articleProjectionMap);  
  17.                 limit = pos + ", 1";  
  18.                 break;  
  19.             }  
  20.             ......  
  21.         }  
  22.   
  23.         Cursor cursor = sqlBuilder.query(db, projection, selection, selectionArgs, nullnull, TextUtils.isEmpty(sortOrder) ? Articles.DEFAULT_SORT_ORDER : sortOrder, limit);  
  24.         ......  
  25.   
  26.         return cursor;  
  27.     }  
  28.   
  29.     ......  
  30. }  
      从前面的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. public class SQLiteQueryBuilder  
  2. {  
  3.     ......  
  4.   
  5.     public Cursor query(SQLiteDatabase db, String[] projectionIn,  
  6.             String selection, String[] selectionArgs, String groupBy,  
  7.             String having, String sortOrder, String limit) {  
  8.         ......  
  9.   
  10.         String sql = buildQuery(  
  11.             projectionIn, selection, groupBy, having,  
  12.             sortOrder, limit);  
  13.   
  14.         ......  
  15.   
  16.         return db.rawQueryWithFactory(  
  17.             mFactory, sql, selectionArgs,  
  18.             SQLiteDatabase.findEditTable(mTables));  
  19.     }  
  20.   
  21.     ......  
  22. }  
      这里首先是调用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. public class SQLiteDatabase extends SQLiteClosable {  
  2.     ......  
  3.   
  4.     public Cursor rawQueryWithFactory(  
  5.             CursorFactory cursorFactory, String sql, String[] selectionArgs,  
  6.             String editTable) {  
  7.         ......  
  8.   
  9.         SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);  
  10.   
  11.         Cursor cursor = null;  
  12.         try {  
  13.             cursor = driver.query(  
  14.                 cursorFactory != null ? cursorFactory : mFactory,  
  15.                 selectionArgs);  
  16.         } finally {  
  17.             ......  
  18.         }  
  19.   
  20.         return cursor;  
  21.     }  
  22.   
  23.     ......  
  24. }  
      这个函数会在内部创建一个SQLiteCursorDriver对象driver,然后调用它的query函数来创建一个Cursor对象,这个Cursor对象的实际类型是SQLiteCursor,下面我们将会看到,前面我们也已经看到,这个SQLiteCursor的内部就包含了一个数据库查询计划。




本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/967007,如需转载请自行联系原作者
目录
相关文章
|
2天前
|
开发工具 Android开发 Windows
Android应用] 问题2:ERROR: unknown virtual device name:
Android应用] 问题2:ERROR: unknown virtual device name:
|
2天前
|
XML JSON API
转Android上基于JSON的数据交互应用
转Android上基于JSON的数据交互应用
|
2天前
|
Android开发
Android应用实例(一)之---有道辞典VZ.0
Android应用实例(一)之---有道辞典VZ.0
|
3天前
|
安全 Java Android开发
构建高效Android应用:采用Kotlin进行内存优化的策略
【5月更文挑战第8天】 在移动开发领域,性能优化一直是开发者关注的焦点。特别是对于Android应用而言,合理管理内存资源是确保应用流畅运行的关键因素之一。近年来,Kotlin作为官方推荐的开发语言,以其简洁、安全和互操作性的特点受到开发者青睐。本文将深入探讨利用Kotlin语言特性,通过具体策略对Android应用的内存使用进行优化,旨在帮助开发者提高应用性能,减少内存消耗,避免常见的内存泄漏问题。
7 0
|
4天前
|
移动开发 数据库 Android开发
构建高效Android应用:Kotlin协程的全面应用
【5月更文挑战第7天】 在移动开发领域,性能优化与流畅的用户体验是至关重要的。随着Kotlin语言的流行,其并发神器——协程,已成为提升Android应用性能的重要工具。本文将深入探讨如何在Android项目中利用Kotlin协程进行异步编程、网络请求和数据库操作,以及如何通过协程简化代码结构,增强应用的响应性和稳定性。我们的目标是为开发者提供一套实用的协程使用模式和最佳实践,以便构建更加高效的Android应用。
20 3
|
8天前
|
存储 安全 Android开发
安卓应用开发:构建一个高效的用户登录系统
【5月更文挑战第3天】在移动应用开发中,用户登录系统的设计与实现是至关重要的一环。对于安卓平台而言,一个高效、安全且用户体验友好的登录系统能够显著提升应用的用户留存率和市场竞争力。本文将探讨在安卓平台上实现用户登录系统的最佳实践,包括对最新身份验证技术的应用、安全性考量以及性能优化策略。
|
11天前
|
前端开发 Android开发 iOS开发
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
【4月更文挑战第30天】Flutter 框架实现跨平台移动应用,通过一致的 UI 渲染(Skia 引擎)、热重载功能和响应式框架提高开发效率和用户体验。然而,Android 和 iOS 的系统差异、渲染机制及编译过程影响性能。性能对比显示,iOS 可能因硬件优化提供更流畅体验,而 Android 更具灵活性和广泛硬件支持。开发者可采用代码、资源优化和特定平台优化策略,利用性能分析工具提升应用性能。
【Flutter前端技术开发专栏】Flutter在Android与iOS上的性能对比
|
12天前
|
监控 Java Android开发
安卓应用开发:打造高效用户界面的五大策略
【4月更文挑战第29天】 在安卓应用开发的世界中,构建一个既美观又高效的用户界面(UI)对于吸引和保留用户至关重要。本文将深入探讨五种策略,这些策略可以帮助开发者优化安卓应用的UI性能。我们将从布局优化讲起,逐步过渡到绘制优化、内存管理、异步处理以及最终的用户交互细节调整。通过这些实践技巧,你将能够为用户提供流畅而直观的体验,确保你的应用在竞争激烈的市场中脱颖而出。
|
1天前
|
Java Android开发
Android开发--Intent-filter属性详解
Android开发--Intent-filter属性详解
|
1天前
|
物联网 Java 开发工具
安卓应用开发:打造未来移动生活
【5月更文挑战第10天】 随着科技的飞速发展,智能手机已成为我们日常生活中不可或缺的一部分。作为智能手机市场的两大巨头,安卓和iOS分别占据了一定的市场份额。在这篇文章中,我们将重点关注安卓应用开发,探讨如何利用先进的技术和创新思维,为用户打造更加便捷、智能的移动生活。文章将涵盖安卓应用开发的基本概念、关键技术、以及未来发展趋势等方面的内容。