Android Jetpack组件之数据库Room详解(二)
本文涉及Library的版本如下:
- androidx.room:room-runtime:2.1.0-alpha03
- androidx.room:room-compiler:2.1.0-alpha03(注解編譯器)
回顧一下安卓的SQLiteOpenHelper相關(guān)類(lèi)
首先放一個(gè)關(guān)于安卓數(shù)據(jù)庫(kù)的類(lèi)圖:
SQLiteOpenHelper是一個(gè)抽象類(lèi),通常自己實(shí)現(xiàn)數(shù)據(jù)庫(kù),需要繼承SQLiteOpenHelper, 在OnCreate()里建表,在onUpgrade()處理版本遷移等。SQLiteOpenHelper是個(gè)幫助類(lèi),里面SQLiteDatabase類(lèi)才是真正代表一個(gè)數(shù)據(jù)庫(kù)。SQLiteDatabase提供了打開(kāi)數(shù)據(jù)庫(kù),增刪改查等方法。我們通常是執(zhí)行sql語(yǔ)句去操作數(shù)據(jù)庫(kù),只不過(guò)官方封裝好更方便使用。
上圖中SQLiteProgram是抽象類(lèi),是編譯SQLite程序的基類(lèi)。成員變量里有sql語(yǔ)句、表字段名數(shù)據(jù),相對(duì)應(yīng)的字段的值。SQLiteStatement繼承SQLiteProgram, 提供一下執(zhí)行語(yǔ)句的方法。SQLiteQurey也是繼承SQLiteProgram,代表了查詢(xún)的執(zhí)行操作。安卓的數(shù)據(jù)庫(kù)操作把查詢(xún)操作和其他操作分開(kāi)。通過(guò)SQLiteDirectCursorDriver驅(qū)動(dòng)執(zhí)行SQLiteQurey生成SQLiteCursor游標(biāo)來(lái)去數(shù)據(jù); 建表,刪表,建索引等是通過(guò)SQLiteStatement.excute()執(zhí)行; 更新和刪除通過(guò)SQLiteStatement.executeUpdateDelete()執(zhí)行; 插入數(shù)據(jù)通過(guò)SQLiteStatement.executeInsert()。Room在原有的基礎(chǔ)上進(jìn)行了封裝。
Room的類(lèi)圖結(jié)構(gòu)
上圖有一些Support開(kāi)頭的接口, 這些接口存在androidx.sqlite:sqlite:2.0.0庫(kù)里, 這個(gè)是對(duì)安卓原有數(shù)據(jù)庫(kù)操作做了接口的抽離。SupportSQLiteDatabase對(duì)應(yīng)SQLiteDatabase,、SupportSQLiteOpenHelper對(duì)應(yīng)SQLiteOpenHelper、SupportSQLiteProgram對(duì)應(yīng)SQLiteProgram等等;
Framework開(kāi)頭一些類(lèi)的是對(duì)一些Support接口的實(shí)現(xiàn);Framework開(kāi)頭這些類(lèi)存在于androidx.sqlite:sqlite-framework:2.0.0庫(kù)中, FrameworkSQLiteDatabase實(shí)現(xiàn)里有個(gè)成員變量SQLiteDatabase,實(shí)現(xiàn)的接口都是交給SQLiteDatabase處理。FrameworkSQLiteOpenHelper、FrameworkSQLiteProgram、FrameworkSQLiteStatement都是這個(gè)套路,使用裝飾者模式,真正的實(shí)現(xiàn)還是安卓原有數(shù)據(jù)庫(kù)操作的類(lèi)。FrameworkSQLiteOpenHelperFactory工廠(chǎng)返回得是FrameworkSQLiteOpenHelper.OpenHelper類(lèi),FrameworkSQLiteOpenHelper.OpenHelper繼承SQLiteOpenHelper。
Room開(kāi)頭這些類(lèi)存在androidx.room:room-runtime:2.10庫(kù)中, 這個(gè)庫(kù)基于Support這類(lèi)接口(例如:SupportSQLiteDatabase)和Framework實(shí)現(xiàn)(FrameworkSQLiteDatabase的實(shí)現(xiàn))再次封裝。room使用過(guò)程中需要定義一個(gè)抽象AppDatabase繼承RoomDatabase,使用Room.databaseBuilder()去生成AppDatabase的實(shí)現(xiàn)。
Room數(shù)據(jù)庫(kù)表的創(chuàng)建
AppDatabase是一個(gè)抽象類(lèi),真正的實(shí)現(xiàn)是AppDatabase_Impl, AppDatabase_Impl是用編譯時(shí)注解生成的,注解編譯器是androidx.room:room-compiler:$room_version。AppDatabase實(shí)現(xiàn)類(lèi)是由RoomDatabase.Builder.build()創(chuàng)建的,先看build方法的實(shí)現(xiàn):
public T build() {......if (mFactory == null) { // SQLiteOpenHelper工廠(chǎng)mFactory = new FrameworkSQLiteOpenHelperFactory();}//DatabaseConfiguration是數(shù)據(jù)配置類(lèi),//存儲(chǔ)context, 數(shù)據(jù)庫(kù)名,SQLiteOpenHelperFactory等參數(shù)DatabaseConfiguration configuration =new DatabaseConfiguration(mContext, mName, mFactory, mMigrationContainer,mCallbacks, mAllowMainThreadQueries, mJournalMode.resolve(mContext),mQueryExecutor,mMultiInstanceInvalidation,mRequireMigration,mAllowDestructiveMigrationOnDowngrade, mMigrationsNotRequiredFrom);//DB_IMPL_SUFFIX = "_Impl", db的實(shí)現(xiàn)是AppDatabase_ImplT db = Room.getGeneratedImplementation(mDatabaseClass, DB_IMPL_SUFFIX);//init方法實(shí)現(xiàn)在RoomDatabasedb.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",反射調(diào)用newInstance()生成實(shí)例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;//是否打開(kāi)日志mOpenHelper.setWriteAheadLoggingEnabled(wal);}mCallbacks = configuration.callbacks;// 查詢(xún)Executor:決定查詢(xún)執(zhí)行的線(xiàn)程mQueryExecutor = configuration.queryExecutor; mAllowMainThreadQueries = configuration.allowMainThreadQueries;mWriteAheadLoggingEnabled = wal;if (configuration.multiInstanceInvalidation) {mInvalidationTracker.startMultiInstanceInvalidation(configuration.context,configuration.name);} }復(fù)制代碼RoomDatabase.createOpenHelper方法是抽象方法,實(shí)現(xiàn)在AppDatabase_Impl, 定位到AppDatabase_Impl.createOpenHelper方法
protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {//_openCallback是局部匿名內(nèi)部實(shí)例, 是一個(gè)RoomOpenHelper實(shí)例, 先不管這個(gè)實(shí)例,接著看下面。final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(1) {public void createAllTables(SupportSQLiteDatabase _db) {//執(zhí)行建表語(yǔ)句_db.execSQL("CREATE TABLE IF NOT EXISTS `User` (`first_name` TEXT, `name` TEXT, `id` INTEGER NOT NULL, PRIMARY KEY(`id`))");}protected void onCreate(SupportSQLiteDatabase _db) {if (mCallbacks != null) {for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {mCallbacks.get(_i).onCreate(_db);}}}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數(shù)據(jù)庫(kù)相關(guān)配置//存儲(chǔ)了context, name(數(shù)據(jù)庫(kù)名字),SupportSQLiteOpenHelper.Callback對(duì)象final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context).name(configuration.name).callback(_openCallback).build();//工廠(chǎng)生成SupportSQLiteOpenHelper, 這里的工廠(chǎng)默認(rèn)是FrameworkSQLiteOpenHelperFactory//默認(rèn)值在RoomDatabase.build()里賦值final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);return _helper;}//FrameworkSQLiteOpenHelperFactory類(lèi)的實(shí)現(xiàn) public final class FrameworkSQLiteOpenHelperFactory implements SupportSQLiteOpenHelper.Factory {public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {//new 一個(gè)FrameworkSQLiteOpenHelper, 接著看FrameworkSQLiteOpenHelper的構(gòu)造器//獲取SupportSQLiteOpenHelper.Configuration的context, name, callbackreturn new FrameworkSQLiteOpenHelper(configuration.context, configuration.name, configuration.callback);} }//FrameworkSQLiteOpenHelper的構(gòu)造器 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的內(nèi)部類(lèi)return new OpenHelper(context, name, dbRef, callback); }//OpenHelper繼承安卓的SQLiteOpenHelper static class OpenHelper extends SQLiteOpenHelper {final FrameworkSQLiteDatabase[] mDbRef;final Callback mCallback;// see b/78359448private boolean mMigrated;OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef,final Callback callback) {super(context, name, null, callback.version,new DatabaseErrorHandler() {public void onCorruption(SQLiteDatabase dbObj) {FrameworkSQLiteDatabase db = dbRef[0];if (db != null) {callback.onCorruption(db);}}});mCallback = callback;mDbRef = dbRef;}public void onCreate(SQLiteDatabase sqLiteDatabase) {//數(shù)據(jù)庫(kù)初始化, mCallback是RoomOpenHelpermCallback.onCreate(getWrappedDb(sqLiteDatabase));} } //RoomOpenHelper.onCreate方法 public void onCreate(SupportSQLiteDatabase db) {//更新Identity(這里跳過(guò),不深入)updateIdentity(db);//mDelegate是RoomOpenHelper的內(nèi)部類(lèi)Delegate, Delegate是一個(gè)抽象類(lèi),//定義了createAllTables, onCreate, onOpen等方法//mDelegate在這里實(shí)現(xiàn)是AppDatabase_Impl.createOpenHelper方法里_openCallback實(shí)例//調(diào)用建表方法mDelegate.createAllTables(db);//調(diào)用onCreate方法mDelegate.onCreate(db);//回看_openCallback實(shí)例的實(shí)現(xiàn), createAllTables里執(zhí)行了建表語(yǔ)句 }復(fù)制代碼Room數(shù)據(jù)庫(kù)插入操作過(guò)程
Room數(shù)據(jù)訪(fǎng)問(wèn)只需要定義一個(gè)DAO接口, 在Dao接口里定義方法以及注解即可。
@Dao public interface UserDao {@Insert(onConflict = OnConflictStrategy.REPLACE)void insert(User user); }//調(diào)用 AppDatabase.getInstance().userDao().insert(user); 復(fù)制代碼前面有說(shuō)到AppDatabase實(shí)現(xiàn)類(lèi)AppDatabase_Impl, 而這里UserDao的實(shí)現(xiàn)類(lèi)是UserDao_Impl。UserDao_Impl也是編譯時(shí)自動(dòng)生成實(shí)現(xiàn)類(lèi),先看一下AppDatabase_Impl.userDao()
public UserDao userDao() {if (_userDao != null) {return _userDao;} else {synchronized(this) {if(_userDao == null) {_userDao = new UserDao_Impl(this);}return _userDao;}}} 復(fù)制代碼接口UserDao_Impl的實(shí)現(xiàn)
//UserDao_Impl構(gòu)造器 public UserDao_Impl(RoomDatabase __db) {this.__db = __db;// 創(chuàng)建一個(gè)EntityInsertionAdapter對(duì)象this.__insertionAdapterOfUser = new EntityInsertionAdapter<User>(__db) {//插入的數(shù)據(jù)的sql語(yǔ)句public String createQuery() {return "INSERT OR ABORT INTO `User`(`first_name`,`name`,`id`) VALUES (?,?,?)";}//綁定插入的字段,對(duì)應(yīng)上面sql語(yǔ)句的‘?’占位符public void bind(SupportSQLiteStatement stmt, User value) {if (value.firstName == null) {stmt.bindNull(1); // 對(duì)應(yīng)第一個(gè)“?”占位符,代表更新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);}}; } public void insert(final User user) {__db.beginTransaction();try { // 開(kāi)啟事務(wù),進(jìn)行插入數(shù)據(jù)__insertionAdapterOfUser.insert(user);__db.setTransactionSuccessful();} finally {__db.endTransaction();}} 復(fù)制代碼從上面的代碼可以知道,最后開(kāi)啟一個(gè)事務(wù),調(diào)用EntityInsertionAdapter.insert方法進(jìn)行數(shù)據(jù)插入, EntityInsertionAdapter是一個(gè)抽象類(lèi),利用泛型封裝了支持所有類(lèi)型的數(shù)據(jù)插入,實(shí)現(xiàn)類(lèi)必須要實(shí)現(xiàn)createQuery和bind兩個(gè)方法。createQuery方法返回一條sql語(yǔ)句,而bind方法是對(duì)數(shù)據(jù)類(lèi)進(jìn)行綁定,和sql語(yǔ)句是一一對(duì)應(yīng)的。
EntityInsertionAdapter.insert方法如下:
public final void insert(T entity) {final SupportSQLiteStatement stmt = acquire(); //創(chuàng)建一個(gè)SupportSQLiteStatement, 這里會(huì)調(diào)用到createQuery方法try {bind(stmt, entity);//會(huì)調(diào)用bind(SupportSQLiteStatement stmt, T value)stmt.executeInsert();//執(zhí)行sql語(yǔ)句} finally {release(stmt);}} 復(fù)制代碼最終數(shù)據(jù)類(lèi)的插入,通過(guò)SupportSQLiteStatement接口去執(zhí)行sql語(yǔ)句。看回本篇文章開(kāi)頭的類(lèi)結(jié)構(gòu)圖,SupportSQLiteStatement是一個(gè)接口, 實(shí)現(xiàn)是FrameworkSQLiteStatement, 而FrameworkSQLiteStatement內(nèi)部實(shí)現(xiàn)是有一個(gè)委派者SQLiteStatement去執(zhí)行的,最終也是調(diào)用安卓原有SQLiteStatement類(lèi)去執(zhí)行。
Room數(shù)據(jù)庫(kù)查詢(xún)過(guò)程
查詢(xún)也類(lèi)似,通過(guò)定義一個(gè)Dao接口和@Query注解,大致代碼如下:
public interface UserDao {("SELECT * FROM user WHERE id = :id")User findById(String id); } 復(fù)制代碼UserDao_Impl.findById實(shí)現(xiàn)如下:
public User findById(final String id) {final String _sql = "SELECT * FROM user WHERE id = ?";//通過(guò)sql創(chuàng)建SQLite查詢(xún)執(zhí)行程序final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);int _argIndex = 1;if (id == null) {_statement.bindNull(_argIndex);} else {_statement.bindString(_argIndex, id);//綁定參數(shù)id}final Cursor _cursor = DBUtil.query(__db, _statement, false);//執(zhí)行查詢(xún)語(yǔ)句//下面通過(guò)cursor獲取數(shù)據(jù)并賦值給Usertry {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();}} 復(fù)制代碼總結(jié)
- Room對(duì)安卓原有的數(shù)據(jù)類(lèi)相關(guān)類(lèi)進(jìn)行一次封裝,對(duì)SQLiteOpenHelper, SQLiteDatabase, SQLiteProgram,SQLiteStatement,SQLiteQurey抽象出了對(duì)應(yīng)的接口SupportSQLiteOpenHelper, SupportSQLiteDatabase, SupportSQLiteProgram, SupportSQLiteStatement, SupportSQLiteQurey。然后提供了一套Framework字母開(kāi)頭的系列類(lèi)是對(duì)Support接口的實(shí)現(xiàn)。
- 抽象出一系列Support接口,可以給開(kāi)發(fā)者去實(shí)現(xiàn)一套不是基于sqlite數(shù)據(jù)庫(kù)。例如可以替代sqlite的開(kāi)源庫(kù)realm
- Room是一個(gè)基于DAO架構(gòu)數(shù)據(jù)庫(kù)框架,利用apt編譯時(shí)自動(dòng)生成代碼來(lái)實(shí)現(xiàn)大量模塊代碼
轉(zhuǎn)載于:https://juejin.im/post/5cb552f3e51d456e6f45c6e4
總結(jié)
以上是生活随笔為你收集整理的Android Jetpack组件之数据库Room详解(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 做梦梦到初中同学是什么意思
- 下一篇: 梦到牙掉茬是什么意思