内容简介:本文涉及Library的版本如下:首先放一个关于安卓数据库的类图:SQLiteOpenHelper是一个抽象类,通常自己实现数据库,需要继承SQLiteOpenHelper, 在OnCreate()里建表,在onUpgrade()处理版本迁移等。SQLiteOpenHelper是个帮助类,里面SQLiteDatabase类才是真正代表一个数据库。SQLiteDatabase提供了打开数据库,增删改查等方法。我们通常是执行sql语句去操作数据库,只不过官方封装好更方便使用。
本文涉及Library的版本如下:
- androidx.room:room-runtime:2.1.0-alpha03
- androidx.room:room-compiler:2.1.0-alpha03(注解编译器)
回顾一下安卓的SQLiteOpenHelper相关类
首先放一个关于安卓数据库的类图:
SQLiteOpenHelper是一个抽象类,通常自己实现数据库,需要继承SQLiteOpenHelper, 在OnCreate()里建表,在onUpgrade()处理版本迁移等。SQLiteOpenHelper是个帮助类,里面SQLiteDatabase类才是真正代表一个数据库。SQLiteDatabase提供了打开数据库,增删改查等方法。我们通常是执行 sql 语句去操作数据库,只不过官方封装好更方便使用。
上图中SQLiteProgram是抽象类,是编译 SQLite 程序的基类。成员变量里有sql语句、表字段名数据,相对应的字段的值。SQLiteStatement继承SQLiteProgram, 提供一下执行语句的方法。SQLiteQurey也是继承SQLiteProgram,代表了查询的执行操作。安卓的数据库操作把查询操作和其他操作分开。通过SQLiteDirectCursorDriver驱动执行SQLiteQurey生成SQLiteCursor游标来去数据; 建表,删表,建索引等是通过SQLiteStatement.excute()执行; 更新和删除通过SQLiteStatement.executeUpdateDelete()执行; 插入数据通过SQLiteStatement.executeInsert()。Room在原有的基础上进行了封装。
Room的类图结构
上图有一些Support开头的接口, 这些接口存在androidx.sqlite:sqlite:2.0.0库里, 这个是对安卓原有数据库操作做了接口的抽离。SupportSQLiteDatabase对应SQLiteDatabase,、SupportSQLiteOpenHelper对应SQLiteOpenHelper、SupportSQLiteProgram对应SQLiteProgram等等;
Framework开头一些类的是对一些Support接口的实现;Framework开头这些类存在于androidx.sqlite:sqlite-framework:2.0.0库中, FrameworkSQLiteDatabase实现里有个成员变量SQLiteDatabase,实现的接口都是交给SQLiteDatabase处理。FrameworkSQLiteOpenHelper、FrameworkSQLiteProgram、FrameworkSQLiteStatement都是这个套路,使用装饰者模式,真正的实现还是安卓原有数据库操作的类。FrameworkSQLiteOpenHelperFactory工厂返回得是FrameworkSQLiteOpenHelper.OpenHelper类,FrameworkSQLiteOpenHelper.OpenHelper继承SQLiteOpenHelper。
Room开头这些类存在androidx.room:room-runtime:2.10库中, 这个库基于Support这类接口(例如:SupportSQLiteDatabase)和Framework实现(FrameworkSQLiteDatabase的实现)再次封装。room使用过程中需要定义一个抽象AppDatabase继承RoomDatabase,使用Room.databaseBuilder()去生成AppDatabase的实现。
Room数据库表的创建
AppDatabase是一个抽象类,真正的实现是AppDatabase_Impl, AppDatabase_Impl是用编译时注解生成的,注解编译器是androidx.room:room-compiler:$room_version。AppDatabase实现类是由RoomDatabase.Builder.build()创建的,先看build方法的实现:
public T build() { ...... if (mFactory == null) { // SQLiteOpenHelper工厂 mFactory = new FrameworkSQLiteOpenHelperFactory(); } //DatabaseConfiguration是数据配置类, //存储context, 数据库名,SQLiteOpenHelperFactory等参数 DatabaseConfiguration configuration = new DatabaseConfiguration(mContext, mName, mFactory, mMigrationContainer, mCallbacks, mAllowMainThreadQueries, mJournalMode.resolve(mContext), mQueryExecutor, mMultiInstanceInvalidation, mRequireMigration, mAllowDestructiveMigrationOnDowngrade, mMigrationsNotRequiredFrom); //DB_IMPL_SUFFIX = "_Impl", db的实现是AppDatabase_Impl T db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX); //init方法实现在RoomDatabase db.init(configuration); return db; } static <T, C> T getGeneratedImplementation(Class<C> klass, String suffix) { final String fullPackage = klass.getPackage().getName(); String name = klass.getCanonicalName(); final String postPackageName = fullPackage.isEmpty() ? name : (name.substring(fullPackage.length() + 1)); final String implName = postPackageName.replace('.', '_') + suffix; // klass的全包名 + "_Impl",反射调用newInstance()生成实例 final Class<T> aClass = (Class<T>) Class.forName( fullPackage.isEmpty() ? implName : fullPackage + "." + implName); return aClass.newInstance(); } //RoomDatabase.init方法 public void init(@NonNull DatabaseConfiguration configuration) { //建表 mOpenHelper = createOpenHelper(configuration); boolean wal = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { wal = configuration.journalMode == JournalMode.WRITE_AHEAD_LOGGING; //是否打开日志 mOpenHelper.setWriteAheadLoggingEnabled(wal); } mCallbacks = configuration.callbacks; // 查询Executor:决定查询执行的线程 mQueryExecutor = configuration.queryExecutor; mAllowMainThreadQueries = configuration.allowMainThreadQueries; mWriteAheadLoggingEnabled = wal; if (configuration.multiInstanceInvalidation) { mInvalidationTracker.startMultiInstanceInvalidation(configuration.context, configuration.name); } } 复制代码
RoomDatabase.createOpenHelper方法是抽象方法,实现在AppDatabase_Impl, 定位到AppDatabase_Impl.createOpenHelper方法
@Override protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) { //_openCallback是局部匿名内部实例, 是一个RoomOpenHelper实例, 先不管这个实例,接着看下面。 final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) { @Override public void createAllTables(SupportSQLiteDatabase _db) { //执行建表语句 _db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`first_name` TEXT, `name` TEXT, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))"); } @Override protected void onCreate(SupportSQLiteDatabase _db) { if (mCallbacks != null) { for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) { mCallbacks.get(_i).onCreate(_db); } } } @Override public void onOpen(SupportSQLiteDatabase _db) { mDatabase = _db; internalInitInvalidationTracker(_db); if (mCallbacks != null) { for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) { mCallbacks.get(_i).onOpen(_db); } } } }, "e216f2ddb0b894667088e1e7fec58cdd", "07bca20d2ba295fc9d4acbe7a3f64d4b"); //SupportSQLiteOpenHelper.Configuration数据库相关配置 //存储了context, name(数据库名字),SupportSQLiteOpenHelper.Callback对象 final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context) .name(configuration.name) .callback(_openCallback) .build(); //工厂生成SupportSQLiteOpenHelper, 这里的工厂默认是FrameworkSQLiteOpenHelperFactory //默认值在RoomDatabase.build()里赋值 final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig); return _helper; } //FrameworkSQLiteOpenHelperFactory类的实现 public final class FrameworkSQLiteOpenHelperFactory implements SupportSQLiteOpenHelper.Factory { @Override public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) { //new 一个FrameworkSQLiteOpenHelper, 接着看FrameworkSQLiteOpenHelper的构造器 //获取SupportSQLiteOpenHelper.Configuration的context, name, callback return new FrameworkSQLiteOpenHelper( configuration.context, configuration.name, configuration.callback); } } //FrameworkSQLiteOpenHelper的构造器 FrameworkSQLiteOpenHelper(Context context, String name, Callback callback) { mDelegate = createDelegate(context, name, callback); } //FrameworkSQLiteOpenHelper.createDelegate方法 private OpenHelper createDelegate(Context context, String name, Callback callback) { final FrameworkSQLiteDatabase[] dbRef = new FrameworkSQLiteDatabase[1]; //OpenHelper是FrameworkSQLiteOpenHelper的内部类 return new OpenHelper(context, name, dbRef, callback); } //OpenHelper继承安卓的SQLiteOpenHelper static class OpenHelper extends SQLiteOpenHelper { final FrameworkSQLiteDatabase[] mDbRef; final Callback mCallback; // see b/78359448 private boolean mMigrated; OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef, final Callback callback) { super(context, name, null, callback.version, new DatabaseErrorHandler() { @Override public void onCorruption(SQLiteDatabase dbObj) { FrameworkSQLiteDatabase db = dbRef[0]; if (db != null) { callback.onCorruption(db); } } }); mCallback = callback; mDbRef = dbRef; } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { //数据库初始化, mCallback是RoomOpenHelper mCallback.onCreate(getWrappedDb(sqLiteDatabase)); } } //RoomOpenHelper.onCreate方法 @Override public void onCreate(SupportSQLiteDatabase db) { //更新Identity(这里跳过,不深入) updateIdentity(db); //mDelegate是RoomOpenHelper的内部类Delegate, Delegate是一个抽象类, //定义了createAllTables, onCreate, onOpen等方法 //mDelegate在这里实现是AppDatabase_Impl.createOpenHelper方法里_openCallback实例 //调用建表方法 mDelegate.createAllTables(db); //调用onCreate方法 mDelegate.onCreate(db); //回看_openCallback实例的实现, createAllTables里执行了建表语句 } 复制代码
Room数据库插入操作过程
Room数据访问只需要定义一个DAO接口, 在Dao接口里定义方法以及注解即可。
@Dao public interface UserDao { @Insert(onConflict = OnConflictStrategy.REPLACE) void insert(User user); } //调用 AppDatabase.getInstance().userDao().insert(user); 复制代码
前面有说到AppDatabase实现类AppDatabase_Impl, 而这里UserDao的实现类是UserDao_Impl。UserDao_Impl也是编译时自动生成实现类,先看一下AppDatabase_Impl.userDao()
@Override public UserDao userDao() { if (_userDao != null) { return _userDao; } else { synchronized(this) { if(_userDao == null) { _userDao = new UserDao_Impl(this); } return _userDao; } } } 复制代码
接口UserDao_Impl的实现
//UserDao_Impl构造器 public UserDao_Impl(RoomDatabase __db) { this.__db = __db; // 创建一个EntityInsertionAdapter对象 this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) { //插入的数据的sql语句 @Override public String createQuery() { return "INSERT OR ABORT INTO `User`(`first_name`,`name`,`id`) VALUES (?,?,?)"; } //绑定插入的字段,对应上面sql语句的‘?’占位符 @Override public void bind(SupportSQLiteStatement stmt, User value) { if (value.firstName == null) { stmt.bindNull(1); // 对应第一个“?”占位符,代表更新first_name的值 } else { stmt.bindString(1, value.firstName); } if (value.name == null) { stmt.bindNull(2); } else { stmt.bindString(2, value.name); } stmt.bindLong(3, value.id); } }; } @Override public void insert(final User user) { __db.beginTransaction(); try { // 开启事务,进行插入数据 __insertionAdapterOfUser.insert(user); __db.setTransactionSuccessful(); } finally { __db.endTransaction(); } } 复制代码
从上面的代码可以知道,最后开启一个事务,调用EntityInsertionAdapter.insert方法进行数据插入, EntityInsertionAdapter是一个抽象类,利用泛型封装了支持所有类型的数据插入,实现类必须要实现createQuery和bind两个方法。createQuery方法返回一条sql语句,而bind方法是对数据类进行绑定,和sql语句是一一对应的。
EntityInsertionAdapter.insert方法如下:
public final void insert(T entity) { final SupportSQLiteStatement stmt = acquire(); //创建一个SupportSQLiteStatement, 这里会调用到createQuery方法 try { bind(stmt, entity);//会调用bind(SupportSQLiteStatement stmt, T value) stmt.executeInsert();//执行sql语句 } finally { release(stmt); } } 复制代码
最终数据类的插入,通过SupportSQLiteStatement接口去执行sql语句。看回本篇文章开头的类结构图,SupportSQLiteStatement是一个接口, 实现是FrameworkSQLiteStatement, 而FrameworkSQLiteStatement内部实现是有一个委派者SQLiteStatement去执行的,最终也是调用安卓原有SQLiteStatement类去执行。
Room数据库查询过程
查询也类似,通过定义一个Dao接口和@Query注解,大致代码如下:
@Dao public interface UserDao { @Query("SELECT * FROM user WHERE id = :id") User findById(String id); } 复制代码
UserDao_Impl.findById实现如下:
@Override public User findById(final String id) { final String _sql = "SELECT * FROM user WHERE id = ?"; //通过sql创建SQLite查询执行程序 final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1); int _argIndex = 1; if (id == null) { _statement.bindNull(_argIndex); } else { _statement.bindString(_argIndex, id);//绑定参数id } final Cursor _cursor = DBUtil.query(__db, _statement, false);//执行查询语句 //下面通过cursor获取数据并赋值给User try { final int _cursorIndexOfFirstName = CursorUtil.getColumnIndexOrThrow(_cursor, "first_name"); final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name"); final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id"); final User _result; if(_cursor.moveToFirst()) { _result = new User(); _result.firstName = _cursor.getString(_cursorIndexOfFirstName); _result.name = _cursor.getString(_cursorIndexOfName); _result.id = _cursor.getInt(_cursorIndexOfId); } else { _result = null; } return _result; } finally { _cursor.close(); _statement.release(); } } 复制代码
总结
- Room对安卓原有的数据类相关类进行一次封装,对SQLiteOpenHelper, SQLiteDatabase, SQLiteProgram,SQLiteStatement,SQLiteQurey抽象出了对应的接口SupportSQLiteOpenHelper, SupportSQLiteDatabase, SupportSQLiteProgram, SupportSQLiteStatement, SupportSQLiteQurey。然后提供了一套Framework字母开头的系列类是对Support接口的实现。
- 抽象出一系列Support接口,可以给开发者去实现一套不是基于sqlite数据库。例如可以替代sqlite的开源库realm
- Room是一个基于DAO架构数据库框架,利用apt编译时自动生成代码来实现大量模块代码
以上所述就是小编给大家介绍的《Android Jetpack组件之数据库Room详解(二)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
QBasic语言程序设计教程(第2版习题解答)
刘瑞新、丁爱萍 / 电子工业出版社 / 1999-6-1 / 13.00
本书是《QBasic语言程序设计教程》(第二版)一书的配套教材、本书第一部分以概要的形式,对全书进行了总结,以便学生复习。在第二部分中,对《QBasic语言程序设计教程》(第二版)中的习题做了详尽的分析与解答。 本书也可作为QBasic语言的习题研单独使用。一起来看看 《QBasic语言程序设计教程(第2版习题解答)》 这本书的介绍吧!