• 11.从架构设计角度分析AAC源码-Room源码解析第0篇:开篇


    前言

    本系列将从无到有一步步解析Room源码。解析过程中,我们始终不要记住,Room其实是对Sqlite的增删改查。只不过加了自己的很多思想去润色。

    正文

    解析顺序,本系列将根据以下系列解说Room源码架构:

    1. 涉及最基础的Sqlite增删改查(Room使用到的增删改查)和对Sqlite的封装(Androidx的Sqlite架构)

    2. 当前demo为主线涉及到的Room源码主线部分解说;

    3. Room compiler代码生成部分源码解说,以及对Room注解根据源码写一个使用文档;

    • room-compiler中androidx.room.parser中的SQLite 文件是如何生成的简单理解一下
    1. Room从架构层面分析;

    Sqlite增删改查

    如果对SQLite的应用不了解,没办法对Room进行解析。

    说明一下几个关于数据库类的关系

    SQLitDatabase家族部分成员,相关类的说明如下(除了下面以外,没做解释的可以不用看,和Room没啥多大关系):

    1. SQLiteOpenHelper是一个帮助(Utility)类,用于方便开发者创建和管理数据库。

    2. SQLiteDatabase代表SQLite数据库,它内部封装了一个Native层的sqlite3实例。

    3. SQLiteStatement用于描述和SQL语句相关的信息。

    4. SQLiteProgram是基类,它提供了一些API用于参数绑定。

    5. SQLiteQuery主要用于query查询操作,而SQLiteStatement用于query之外的一些操作(根据SDK的说明,如果SQLiteStatement用于query查询,其返回的结果集只能是1行*1列)。

    demo应用

    当前数据库存在demo.db数据库文件中,一个用户表users:userid和username两个字段,userid表示主键。实现如下:

    1. 创建数据库文件,并获取SQLiteDatabase数据库对象:

       public class OpenHelper extends SQLiteOpenHelper{
       
       	final Context mContext;
       
       	public OpenHelper(Context context, String name,int version){
       		super(context,name,null,version);
       		mContext = context;
       	}
       
       	public SQLiteDatabase getSQLiteDatabase(boolean writele){
       		String name = getDatabaseName();
               if (name != null) {
                   //数据库文件如果不存在,那么新建
                   File databaseFile = mContext.getDatabasePath(name);
                   File parentFile = databaseFile.getParentFile();
                   if (parentFile != null) {
                       parentFile.mkdirs();
                       if (!parentFile.isDirectory()) {
                           Log.w(TAG, "Invalid database parent file, not a directory: " + parentFile);
                       }
                   }
               }
       
               try {
                   return getWritableOrReadableDatabase(writable);
               } catch (Throwable t) {
                   // No good, just try again...
                   super.close();
               }
       		return null;
       	}
       
       	public SQLiteDatabase getWritableOrReadableDatabase(boolean writable) {
               if (writable) {
                   return super.getWritableDatabase();
               } else {
                   return super.getReadableDatabase();
               }
           }
       }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40

      //实例化OpenHelper,并且操作SQLiteDatabase都是在该类中通过getWritableOrReadableDatabase(writable)获取读写权限
      OpenHelper openHelper = new OpenHelper(context,“demo.db”,1);

    2. 添加和修改SQLite数据库 - 插入先开启事务,事务提示成功,最后结束事务:

       private void insert(User user){
       	SQLiteDatabase sqliteDatabase = openHelper.getSupportDatabase(true);
       	
       	sqliteDatabase.beginTransaction();
       	 try {
             insertUser(sqliteDatabase,user);
             sqliteDatabase.setTransactionSuccessful();
             return null;
           } finally {
             sqliteDatabase.endTransaction();
           }
      
       }
      
       private void insertUser(SQLiteDatabase sqliteDatabase,User user){
      
       	String query = "INSERT OR REPLACE INTO `users` (`userid`,`username`) VALUES (?,?)";
      
       	//compileStatement方法为了SQLiteStatement可重复利用
       	SQLiteStatement sqliteStatement = sqliteDatabase.compileStatement(query);
      
       	bind( stmt,  value);
       	stmt.executeInsert();
       }
      
       private void bind(SQLiteStatement stmt, User value) {
           if (value.getId() == null) {
             stmt.bindNull(1);
           } else {
             stmt.bindString(1, value.getId());
           }
           if (value.getUserName() == null) {
             stmt.bindNull(2);
           } else {
             stmt.bindString(2, value.getUserName());
           }
      
       	
         }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 如果userid相同,则覆盖;否则新建
    3. 删除SQLite,这个是删除表,删除某个字段应该也比较简单,修改query = "delete from users where userid = xxx"即可

       private void deleteUserTable(SQLiteStatement stmt){
       	String query = "DELETE FROM Users";
       	
       	//compileStatement方法为了SQLiteStatement可重复利用
       	SQLiteStatement sqliteStatement = sqliteDatabase.compileStatement(query);
       
       	SQLiteDatabase sqliteDatabase = openHelper.getSupportDatabase(true);
       			
       	sqliteDatabase.beginTransaction();
       	 try {
             stmt.executeUpdateDelete();
             sqliteDatabase.setTransactionSuccessful();
            
           } finally {
             sqliteDatabase.endTransaction();
           }
       }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    4. 查询SQLite

      public User getUser(SQLiteDatabase sqliteDatabase){
      final String sql = “SELECT * FROM Users LIMIT 1”;

       final Cursor cursor =sqliteDatabase.rawQuery(sql,null);
      
       try {
         final int cursorIndexOfMId = CursorUtil.getColumnIndexOrThrow(cursor, "userid");
         final int cursorIndexOfMUserName = CursorUtil.getColumnIndexOrThrow(cursor, "username");
         final User result;
         if(cursor.moveToFirst()) {
           final String _tmpMId;
           if (cursor.isNull(cursorIndexOfMId)) {
             tmpMId = null;
           } else {
             tmpMId = cursor.getString(cursorIndexOfMId);
           }
           final String tmpMUserName;
           if (cursor.isNull(cursorIndexOfMUserName)) {
             tmpMUserName = null;
           } else {
             tmpMUserName = cursor.getString(cursorIndexOfMUserName);
           }
           result = new User(tmpMId,tmpMUserName);
         } else {
           result = null;
         }
         return result;
       } finally {
         cursor.close();
       }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27

      }

    代码是从源码你们抠出来的,理解起来也应该非常简单,这里理解对后面的源码理解有好处。

    androidx中Sqlite架构源码解析

    sqlite源码我只针对sqlite和sqlite-framework进行讲解:这两部分代码量也非常小,虽然简单,但对后面Room的理解至关重要。

    sqlite

    该模块主要启到规范使用SQLite的作用,当前操作SupportSQLite替代SQLite,省去其他SQLite中不必要的一些方法。

    1. SupportSQLiteOpenHelper接口:该接口定义了操作SupportSQLiteDatabase类的一些方法(最主要的是getWritableDatabase和getReadableDatabase,分别表示读写权限的数据库),另外有一些其他类或接口;
    • Callback抽象类:传入当前操作的数据库版本,用于对数据库的创建、打开、升级、降级、文件损坏处理;

    • Configuration类:创建sqliteOpenHelper类时的参数这里配置;

    • Builder类:使用构建者模式实例化Configuration类;

    • Factory接口:创建当前SupportSQLiteOpenHelper实例,传递Configuration类提供参数;

    1. SupportSQLiteDatabase接口:数据库操作方法,这里的方法和SQLiteDatabase基本一致;

    2. SupportSQLiteProgram接口:数据库字段绑定,根据字段类型,选取绑定类型,例如bindLong(int index,long value),表示当前绑定的字段是long类型,参数index表示当前字段处于数据库表中的位置;

    3. SupportSQLiteQuery接口:数据库query工作;

    4. SupportSQLiteStatement接口:规范数据库增删改查执行方法;

    5. SupportSQLiteCompat类:SQLiteDatabase兼容性处理;

    6. SimpleSQLiteQuery类:当前类继承SupportSQLiteQuery接口,存取sqlite的query和根据输入字段数组,确定SupportSQLiteProgram接口中的绑定类型;

    7. SupportSQLiteQueryBuilder类:构建者模式新建一个SimpleSQLiteQuery类,该类用于查询表中字段信息,可以实现精确查询。

    以上说的非常非常抽象,可以按照SQLite去理解。不比过于纠结,我们继续看sqlite-framework(也是一个比较抽象的模块)

    sqlite-framework

    当前模块比较重要的特点:1. 继承sqlite模块下的接口;2. 采用代理模式执行代理方法;

    1. FrameworkSQLiteOpenHelperFactory类:工厂模式创建FrameworkSQLiteOpenHelper类;

    2. FrameworkSQLiteDatabase类:该类传递一个SQLiteDatabase数据库类作为代理对象delegate,继承SupportSQLiteDatabase接口,实现该接口的所有操作数据库方法,这些方法其实还是操作代理delegate的方法;

    3. FrameworkSQLiteProgram类:构造函数传递SQLiteProgram对象作为delegate代理,继承SupportSQLiteProgram接口,该接口实现方法实际操作的是delegate代理的相应方法;

    4. FrameworkSQLiteStatement类:继承FrameworkSQLiteProgram类,用于精确执行sql;构造函数传递SQLiteStatement delegate代理对象,该类继承SupportSQLiteStatement接口执行的实现方法最终执行的还是delegate代理的相应方法;

    5. FrameworkSQLiteOpenHelper类:该类只管重要

    • (1)当前类生成一个OpenHelper代理对象,该对象继承SQLiteOpenHelper类,所以实际实例化的是SQLiteOpenHelper类;
    • (2)OpenHelper类中创建FrameworkSQLiteDatabase实例,在SQLiteOpenHelper类中获取读写权限的SQLiteDatabase作为FrameworkSQLiteDatabase的构造函数参数;
    • (3)FrameworkSQLiteOpenHelper类继承SupportSQLiteOpenHelper接口,它操控的SupportSQLiteDatabase接口实际就是FrameworkSQLiteDatabase类;
    • (4)FrameworkSQLiteDatabase通过compileStatement方法返回SupportSQLiteStatement,同时将SQLiteStatement对象作为FrameworkSQLiteStatement构造函数的参数;
    • (5)为什么要使用OpenHelper类而不是直接使用SQLiteOpenHelper类?因为对sqlite的实际操作(创建,打开,升级,降级)都是通过回调Callback抽象类的相应方法去实现;

    怎么说了感觉和没说一个样!!!我在哪?我是谁???我在干啥!!!

    当前模块同样的比较抽象。可以从FrameworkSQLiteOpenHelper类的getDelegate方法为切入点去摸索,看个大概,我们继续往下才能明白人家具体含义。

    参考

    1. Android内置SQLite的使用(超详细)

    2. SQLite–SQLiteDatabase、SQLiteOpenHelper、sqlite3.c–(jni、头文件)–源码分析基于Android M

    3. SQLiteDataBase事务

    总结

    代码还得仔细看下,因为后面room实际操作的就是sqlite-framework中的各个实现类,入口当然是FrameworkSQLiteOpenHelperFactory,新建一个操作FrameworkSQLiteDatabase类的FrameworkSQLiteOpenHelper类。

    在思考一个问题,sqlite和sqlite-framework有必要吗?我直接使用SQlite不是更好,为什么要使用这里的SupportSqlite:通过一系列代理,实际执行的还是SQLite。

  • 相关阅读:
    汇编视角分析C++虚函数实现原理
    第四天:gec6818开发板串口蓝牙模块的使用与配置
    【题解】Educational Codeforces Round 142(CF1792)
    【深度学习】 Python 和 NumPy 系列教程(八):Python类
    Matlab:基于Matlab实现人工智能算法应用的简介(SVM支撑向量机&GA遗传算法&PSO粒子群优化算法)、案例应用之详细攻略
    孔乙己脱不下的长衫:人工智能对学历的看法
    呼叫中心的实时语音分析
    毕业设计 LSTM的预测算法 - 股票预测 天气预测 房价预测
    计算机网络必须知道的点
    一个 不用充钱 也能让你变强的 VSCode 插件
  • 原文地址:https://blog.csdn.net/foshengtang/article/details/126865342