前言
本系列将从无到有一步步解析Room源码。解析过程中,我们始终不要记住,Room其实是对Sqlite的增删改查。只不过加了自己的很多思想去润色。
正文
解析顺序,本系列将根据以下系列解说Room源码架构:
-
涉及最基础的Sqlite增删改查(Room使用到的增删改查)和对Sqlite的封装(Androidx的Sqlite架构)
-
当前demo为主线涉及到的Room源码主线部分解说;
-
Room compiler代码生成部分源码解说,以及对Room注解根据源码写一个使用文档;
- room-compiler中androidx.room.parser中的SQLite 文件是如何生成的简单理解一下
- Room从架构层面分析;
Sqlite增删改查
如果对SQLite的应用不了解,没办法对Room进行解析。
说明一下几个关于数据库类的关系
SQLitDatabase家族部分成员,相关类的说明如下(除了下面以外,没做解释的可以不用看,和Room没啥多大关系):
-
SQLiteOpenHelper是一个帮助(Utility)类,用于方便开发者创建和管理数据库。
-
SQLiteDatabase代表SQLite数据库,它内部封装了一个Native层的sqlite3实例。
-
SQLiteStatement用于描述和SQL语句相关的信息。
-
SQLiteProgram是基类,它提供了一些API用于参数绑定。
-
SQLiteQuery主要用于query查询操作,而SQLiteStatement用于query之外的一些操作(根据SDK的说明,如果SQLiteStatement用于query查询,其返回的结果集只能是1行*1列)。
demo应用
当前数据库存在demo.db数据库文件中,一个用户表users:userid和username两个字段,userid表示主键。实现如下:
-
创建数据库文件,并获取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(); } } }
//实例化OpenHelper,并且操作SQLiteDatabase都是在该类中通过getWritableOrReadableDatabase(writable)获取读写权限
OpenHelper openHelper = new OpenHelper(context,“demo.db”,1); -
添加和修改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()); } }
- 如果userid相同,则覆盖;否则新建
-
删除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(); } }
-
查询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(); }
}
代码是从源码你们抠出来的,理解起来也应该非常简单,这里理解对后面的源码理解有好处。
androidx中Sqlite架构源码解析
sqlite源码我只针对sqlite和sqlite-framework进行讲解:这两部分代码量也非常小,虽然简单,但对后面Room的理解至关重要。
sqlite
该模块主要启到规范使用SQLite的作用,当前操作SupportSQLite替代SQLite,省去其他SQLite中不必要的一些方法。
- SupportSQLiteOpenHelper接口:该接口定义了操作SupportSQLiteDatabase类的一些方法(最主要的是getWritableDatabase和getReadableDatabase,分别表示读写权限的数据库),另外有一些其他类或接口;
-
Callback抽象类:传入当前操作的数据库版本,用于对数据库的创建、打开、升级、降级、文件损坏处理;
-
Configuration类:创建sqliteOpenHelper类时的参数这里配置;
-
Builder类:使用构建者模式实例化Configuration类;
-
Factory接口:创建当前SupportSQLiteOpenHelper实例,传递Configuration类提供参数;
-
SupportSQLiteDatabase接口:数据库操作方法,这里的方法和SQLiteDatabase基本一致;
-
SupportSQLiteProgram接口:数据库字段绑定,根据字段类型,选取绑定类型,例如bindLong(int index,long value),表示当前绑定的字段是long类型,参数index表示当前字段处于数据库表中的位置;
-
SupportSQLiteQuery接口:数据库query工作;
-
SupportSQLiteStatement接口:规范数据库增删改查执行方法;
-
SupportSQLiteCompat类:SQLiteDatabase兼容性处理;
-
SimpleSQLiteQuery类:当前类继承SupportSQLiteQuery接口,存取sqlite的query和根据输入字段数组,确定SupportSQLiteProgram接口中的绑定类型;
-
SupportSQLiteQueryBuilder类:构建者模式新建一个SimpleSQLiteQuery类,该类用于查询表中字段信息,可以实现精确查询。
以上说的非常非常抽象,可以按照SQLite去理解。不比过于纠结,我们继续看sqlite-framework(也是一个比较抽象的模块)
sqlite-framework
当前模块比较重要的特点:1. 继承sqlite模块下的接口;2. 采用代理模式执行代理方法;
-
FrameworkSQLiteOpenHelperFactory类:工厂模式创建FrameworkSQLiteOpenHelper类;
-
FrameworkSQLiteDatabase类:该类传递一个SQLiteDatabase数据库类作为代理对象delegate,继承SupportSQLiteDatabase接口,实现该接口的所有操作数据库方法,这些方法其实还是操作代理delegate的方法;
-
FrameworkSQLiteProgram类:构造函数传递SQLiteProgram对象作为delegate代理,继承SupportSQLiteProgram接口,该接口实现方法实际操作的是delegate代理的相应方法;
-
FrameworkSQLiteStatement类:继承FrameworkSQLiteProgram类,用于精确执行sql;构造函数传递SQLiteStatement delegate代理对象,该类继承SupportSQLiteStatement接口执行的实现方法最终执行的还是delegate代理的相应方法;
-
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方法为切入点去摸索,看个大概,我们继续往下才能明白人家具体含义。
参考
总结
代码还得仔细看下,因为后面room实际操作的就是sqlite-framework中的各个实现类,入口当然是FrameworkSQLiteOpenHelperFactory,新建一个操作FrameworkSQLiteDatabase类的FrameworkSQLiteOpenHelper类。
在思考一个问题,sqlite和sqlite-framework有必要吗?我直接使用SQlite不是更好,为什么要使用这里的SupportSqlite:通过一系列代理,实际执行的还是SQLite。