Jetpack系列-Room使用和源码分析

1 简介

Room是Google官方在SQLite基础上封装的一款数据持久库,是Jetpack全家桶的一员,和Jetpack其他库有着可以高度搭配协调的天然优势。Room使用APT技术,大大简化了使用SQLite的代码量,只需使用注解配合少量代码即可实现高效的数据库操作。

优点:

  • Google官方库,和Jetpack其他库(比如Lifecycle,LiveData)等有天然的融合搭配使用优势。
  • 在编译器可以对SQL语法进行检查。
  • 使用APT,简单地几个注解搭配少量代码即可使用,大量减少模板代码。
  • 查询代码自定义,可以实现更复杂的查询功能,也可以对SQL语句进行优化。
  • 简化数据库的迁移路径。

不足:

  • 查询时必须手动写SQL语句,不提供默认的查询配置。
  • 效率比其他数据库框架(GreenDao等)并没有多少提高。
  • 数据库版本升级稍显复杂。

Google官方文档:developer.android.com/jetpack/and…

2 主要组件

Room 包含三个主要组件:

  • DataBase:数据库类,用@Database标注,继承RoomDatabase,用于保存数据库并作为应用持久性数据底层连接的主要访问点。
  • Entity:数据实体,用@Entity标注,用于表示应用的数据库中的表。
  • Data Access Object:数据访问对象 (DAO),用@DAO标注,提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。

在DataBase中获取DAO,然后在业务层使用DAO去进行数据的操作。

3 单独使用Room

在Module的build.gradle下添加APT支持。

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-kapt'
}

在Module的build.gradle下引入依赖。

def room_version = "2.4.2"

implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"

创建数据实体Book,包含bookId,name,author,price4个字段,由于bookId被设为主键,需要自增长,所以构造方法里不能有bookId。

@Entity标注Book,就表示在数据库中创建了一个名为“Book”的表。

@PrimaryKey设置该字段是主键,autoGenerate = true表示主键自增长,bookId会从1开始,每插入一条数据就会+1.

@ColumnInfo设置该字段在数据库中的列名,name后的值就是在数据库中的列名。@ColumnInfo可选,不添加的话数据库列名和实体字段名一致。

@Entity
class Book(
    var name: String,
    @field:ColumnInfo(name = "author") var author: String,
    @field:ColumnInfo(name = "price") var price: Float
) {
    @PrimaryKey(autoGenerate = true)
    var bookId = 0
    
    
    override fun toString(): String {
        return "Book(name='$name', author='$author', price=$price, bookId=$bookId)"
    }
}

接着创建一个接口类DAO,在DAO中定义数据库操作方法。用@Dao来标注,然后定义接口方法操作数据库,用对应的注解标注,增删改查分别对应@Insert@Delete@Update@Query

@Dao
interface BookDao {

    @Insert
    fun insert(book: Book)

    @Delete
    fun delete(book: Book)

    @Update
    fun update(book: Book)

    //根据名字查数据
    @Query("select * from Book where name like:name")
    fun queryBookByName(name: String): MutableList<Book>

    //根据一组id查数据
    @Query("select * from Book where bookId in(:bookIds)")
    fun queryBookByIds(bookIds: Array<Int>): MutableList<Book>

    //查询所有数据
    @Query("select * from Book")
    fun queryAllBook(): MutableList<Book>

    //查询所有数据中的name和author
    @Query("select name,author from Book")
    fun queryBookWithPartFiled(): MutableList<Book2>
    
}

然后创建DataBase,继承RoomDatabase,用注解@Database标注,entities后的值表示数据库中的实体,也就是表,可以有多个,version是数据库版本,exportSchema表示是否支持导出,如果没有指定数据库导出路径,需要设置为false,不然会报错。数据库导出请看文档:developer.android.com/jetpack/and…

DataBase中提供了一个方法获取DAO。

@Database(entities = [Book::class], version = 1, exportSchema = false)
abstract class AppDataBase : RoomDatabase() {
    abstract fun bookDao(): BookDao
}

最后在Activity初始化数据库并使用。数据库初始化方法是Room.databaseBuilder(Context context, Class<T> klass, String name),3个参数分别是上下文,DataBase类,数据库名称。

class MainActivity : AppCompatActivity() {
    
    private val TAG = "---MS---"
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        //Room默认需要在子线程使用
        thread {
            val database =
            Room.databaseBuilder(applicationContext, AppDataBase::class.java, "MsDB")
            //                    .allowMainThreadQueries()//如果需要在主线程中使用,可以开启这行代码
                .build()
            val dao = database.bookDao()
            
            //插入4条数据
            dao.insert(Book("三体", "刘慈欣", 55.6f))
            dao.insert(Book("黄金时代", "王小波", 32.9f))
            dao.insert(Book("生死疲劳", "莫言", 32.9f))
            dao.insert(Book("一句顶一万句", "刘震云", 32.9f))
            
            Log.d(TAG, "查询名字为三体发的数据: ${dao.queryBookByName("三体")}")
            Log.d(TAG, "查询id为1,3,4的数据: ${dao.queryBookByIds(arrayOf(1, 3, 4))}")
            Log.d(TAG, "查询所有数据: ${dao.queryAllBook()}")
            Log.d(TAG, "查询name和author: ${dao.queryBookWithPartFiled()}")
            
        }
    }
}

回到BookDao中可以看到,queryBookWithPartFiled方法查询的不是Book表中所有列,而是name和author这两列,返回的对象是Book2,不是Book。这是因为Room查询的时候,查询的列必须和返回的实体中所有字段对应,这也是Room的一个弊端之一。所以这里又定义了一个Book2,用来接收查询到的数据,Book2中只有两个字段name和author,并且不能用@Entity标注,不然Book2也变成了数据库中的一张表。

class Book2(
    var name: String,
    @field:ColumnInfo(name = "author") var author: String,
) {
    override fun toString(): String {
        return "Book2(name='$name', author='$author')"
    }
}

4 数据库版本升级

Room的数据库版本升级稍显麻烦,核心是Migration类。

修改实体类,新增一个publishData字段。

@Entity
class Book(
    var name: String,
    @field:ColumnInfo(name = "author") var author: String,
    @field:ColumnInfo(name = "price") var price: Float,
    //新增字段
    @field:ColumnInfo(name = "data") var publishData: String
) {
    @PrimaryKey(autoGenerate = true)
    var bookId = 0
    
    
    override fun toString(): String {
        return "Book(name='$name', author='$author', price=$price, bookId=$bookId)"
    }
}

然后把version改为2。

@Database(entities = [Book::class], version = 2, exportSchema = false)
abstract class AppDataBase : RoomDatabase() {
    abstract fun bookDao(): BookDao
}

定义一个内部类,继承Migration,实现migrate方法,执行语句往表中添加列。

/**
* 从版本1升级到版本2
*/
inner class Migration1To2 : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        //执行sql语句,添加data列
        database.execSQL("alter table book add column data TEXT not null default '2020-05-01' ")
    }
}

最后在Room初始化的时候添加.addMigrations(Migration1To2())

val database =
    Room.databaseBuilder(applicationContext, AppDataBase::class.java, "MsDB")
//                    .allowMainThreadQueries()//如果需要在主线程中使用,可以开启这行代码
    //升级
    .addMigrations(Migration1To2())
                    .build()

5 源码分析

Room使用APT技术,提供了大量的注解。

当用@Dao标注BookDao类,会在build/generated/source/kapt/debug/包名/下生成BookDao_impl.java。该类实现了BookDao中所有的接口方法,实现了具体的增删改查方法。

package cn.zhangmushui.room;

import android.database.Cursor;
import androidx.room.EntityDeletionOrUpdateAdapter;
import androidx.room.EntityInsertionAdapter;
import androidx.room.RoomDatabase;
import androidx.room.RoomSQLiteQuery;
import androidx.room.util.CursorUtil;
import androidx.room.util.DBUtil;
import androidx.room.util.StringUtil;
import androidx.sqlite.db.SupportSQLiteStatement;
import java.lang.Class;
import java.lang.Integer;
import java.lang.Override;
import java.lang.String;
import java.lang.StringBuilder;
import java.lang.SuppressWarnings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@SuppressWarnings({"unchecked", "deprecation"})
public final class BookDao_Impl implements BookDao {
    private final RoomDatabase __db;
    
    private final EntityInsertionAdapter<Book> __insertionAdapterOfBook;
    
    private final EntityDeletionOrUpdateAdapter<Book> __deletionAdapterOfBook;
    
    private final EntityDeletionOrUpdateAdapter<Book> __updateAdapterOfBook;
    
    public BookDao_Impl(RoomDatabase __db) {
        this.__db = __db;
        this.__insertionAdapterOfBook = new EntityInsertionAdapter<Book>(__db) {
            @Override
            public String createQuery() {
                return "INSERT OR ABORT INTO `Book` (`name`,`author`,`price`,`data`,`bookId`) VALUES (?,?,?,?,nullif(?, 0))";
            }
            
            @Override
            public void bind(SupportSQLiteStatement stmt, Book value) {
                if (value.getName() == null) {
                    stmt.bindNull(1);
                } else {
                    stmt.bindString(1, value.getName());
                }
                if (value.getAuthor() == null) {
                    stmt.bindNull(2);
                } else {
                    stmt.bindString(2, value.getAuthor());
                }
                stmt.bindDouble(3, value.getPrice());
                if (value.getPublishData() == null) {
                    stmt.bindNull(4);
                } else {
                    stmt.bindString(4, value.getPublishData());
                }
                stmt.bindLong(5, value.getBookId());
            }
        };
        this.__deletionAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
            @Override
            public String createQuery() {
                return "DELETE FROM `Book` WHERE `bookId` = ?";
            }
            
            @Override
            public void bind(SupportSQLiteStatement stmt, Book value) {
                stmt.bindLong(1, value.getBookId());
            }
        };
        this.__updateAdapterOfBook = new EntityDeletionOrUpdateAdapter<Book>(__db) {
            @Override
            public String createQuery() {
                return "UPDATE OR ABORT `Book` SET `name` = ?,`author` = ?,`price` = ?,`data` = ?,`bookId` = ? WHERE `bookId` = ?";
            }
            
            @Override
            public void bind(SupportSQLiteStatement stmt, Book value) {
                if (value.getName() == null) {
                    stmt.bindNull(1);
                } else {
                    stmt.bindString(1, value.getName());
                }
                if (value.getAuthor() == null) {
                    stmt.bindNull(2);
                } else {
                    stmt.bindString(2, value.getAuthor());
                }
                stmt.bindDouble(3, value.getPrice());
                if (value.getPublishData() == null) {
                    stmt.bindNull(4);
                } else {
                    stmt.bindString(4, value.getPublishData());
                }
                stmt.bindLong(5, value.getBookId());
                stmt.bindLong(6, value.getBookId());
            }
        };
    }
    
    @Override
    public void insert(final Book book) {
        __db.assertNotSuspendingTransaction();
        __db.beginTransaction();
        try {
            __insertionAdapterOfBook.insert(book);
            __db.setTransactionSuccessful();
        } finally {
            __db.endTransaction();
        }
    }
    
    @Override
    public void delete(final Book book) {
        __db.assertNotSuspendingTransaction();
        __db.beginTransaction();
        try {
            __deletionAdapterOfBook.handle(book);
            __db.setTransactionSuccessful();
        } finally {
            __db.endTransaction();
        }
    }
    
    @Override
    public void update(final Book book) {
        __db.assertNotSuspendingTransaction();
        __db.beginTransaction();
        try {
            __updateAdapterOfBook.handle(book);
            __db.setTransactionSuccessful();
        } finally {
            __db.endTransaction();
        }
    }
    
    @Override
    public List<Book> queryBookByName(final String name) {
        final String _sql = "select * from Book where name like?";
        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
        int _argIndex = 1;
        if (name == null) {
            _statement.bindNull(_argIndex);
        } else {
            _statement.bindString(_argIndex, name);
        }
        __db.assertNotSuspendingTransaction();
        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
        try {
            final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
            final int _cursorIndexOfAuthor = CursorUtil.getColumnIndexOrThrow(_cursor, "author");
            final int _cursorIndexOfPrice = CursorUtil.getColumnIndexOrThrow(_cursor, "price");
            final int _cursorIndexOfPublishData = CursorUtil.getColumnIndexOrThrow(_cursor, "data");
            final int _cursorIndexOfBookId = CursorUtil.getColumnIndexOrThrow(_cursor, "bookId");
            final List<Book> _result = new ArrayList<Book>(_cursor.getCount());
            while(_cursor.moveToNext()) {
                final Book _item;
                final String _tmpName;
                if (_cursor.isNull(_cursorIndexOfName)) {
                    _tmpName = null;
                } else {
                    _tmpName = _cursor.getString(_cursorIndexOfName);
                }
                final String _tmpAuthor;
                if (_cursor.isNull(_cursorIndexOfAuthor)) {
                    _tmpAuthor = null;
                } else {
                    _tmpAuthor = _cursor.getString(_cursorIndexOfAuthor);
                }
                final float _tmpPrice;
                _tmpPrice = _cursor.getFloat(_cursorIndexOfPrice);
                final String _tmpPublishData;
                if (_cursor.isNull(_cursorIndexOfPublishData)) {
                    _tmpPublishData = null;
                } else {
                    _tmpPublishData = _cursor.getString(_cursorIndexOfPublishData);
                }
                _item = new Book(_tmpName,_tmpAuthor,_tmpPrice,_tmpPublishData);
                final int _tmpBookId;
                _tmpBookId = _cursor.getInt(_cursorIndexOfBookId);
                _item.setBookId(_tmpBookId);
                _result.add(_item);
            }
            return _result;
        } finally {
            _cursor.close();
            _statement.release();
        }
    }
    
    @Override
    public List<Book> queryBookByIds(final Integer[] bookIds) {
        StringBuilder _stringBuilder = StringUtil.newStringBuilder();
        _stringBuilder.append("select * from Book where bookId in(");
        final int _inputSize = bookIds.length;
        StringUtil.appendPlaceholders(_stringBuilder, _inputSize);
        _stringBuilder.append(")");
        final String _sql = _stringBuilder.toString();
        final int _argCount = 0 + _inputSize;
        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, _argCount);
        int _argIndex = 1;
        for (Integer _item : bookIds) {
            if (_item == null) {
                _statement.bindNull(_argIndex);
            } else {
                _statement.bindLong(_argIndex, _item);
            }
            _argIndex ++;
        }
        __db.assertNotSuspendingTransaction();
        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
        try {
            final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
            final int _cursorIndexOfAuthor = CursorUtil.getColumnIndexOrThrow(_cursor, "author");
            final int _cursorIndexOfPrice = CursorUtil.getColumnIndexOrThrow(_cursor, "price");
            final int _cursorIndexOfPublishData = CursorUtil.getColumnIndexOrThrow(_cursor, "data");
            final int _cursorIndexOfBookId = CursorUtil.getColumnIndexOrThrow(_cursor, "bookId");
            final List<Book> _result = new ArrayList<Book>(_cursor.getCount());
            while(_cursor.moveToNext()) {
                final Book _item_1;
                final String _tmpName;
                if (_cursor.isNull(_cursorIndexOfName)) {
                    _tmpName = null;
                } else {
                    _tmpName = _cursor.getString(_cursorIndexOfName);
                }
                final String _tmpAuthor;
                if (_cursor.isNull(_cursorIndexOfAuthor)) {
                    _tmpAuthor = null;
                } else {
                    _tmpAuthor = _cursor.getString(_cursorIndexOfAuthor);
                }
                final float _tmpPrice;
                _tmpPrice = _cursor.getFloat(_cursorIndexOfPrice);
                final String _tmpPublishData;
                if (_cursor.isNull(_cursorIndexOfPublishData)) {
                    _tmpPublishData = null;
                } else {
                    _tmpPublishData = _cursor.getString(_cursorIndexOfPublishData);
                }
                _item_1 = new Book(_tmpName,_tmpAuthor,_tmpPrice,_tmpPublishData);
                final int _tmpBookId;
                _tmpBookId = _cursor.getInt(_cursorIndexOfBookId);
                _item_1.setBookId(_tmpBookId);
                _result.add(_item_1);
            }
            return _result;
        } finally {
            _cursor.close();
            _statement.release();
        }
    }
    
    @Override
    public List<Book> queryAllBook() {
        final String _sql = "select * from Book";
        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
        __db.assertNotSuspendingTransaction();
        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
        try {
            final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
            final int _cursorIndexOfAuthor = CursorUtil.getColumnIndexOrThrow(_cursor, "author");
            final int _cursorIndexOfPrice = CursorUtil.getColumnIndexOrThrow(_cursor, "price");
            final int _cursorIndexOfPublishData = CursorUtil.getColumnIndexOrThrow(_cursor, "data");
            final int _cursorIndexOfBookId = CursorUtil.getColumnIndexOrThrow(_cursor, "bookId");
            final List<Book> _result = new ArrayList<Book>(_cursor.getCount());
            while(_cursor.moveToNext()) {
                final Book _item;
                final String _tmpName;
                if (_cursor.isNull(_cursorIndexOfName)) {
                    _tmpName = null;
                } else {
                    _tmpName = _cursor.getString(_cursorIndexOfName);
                }
                final String _tmpAuthor;
                if (_cursor.isNull(_cursorIndexOfAuthor)) {
                    _tmpAuthor = null;
                } else {
                    _tmpAuthor = _cursor.getString(_cursorIndexOfAuthor);
                }
                final float _tmpPrice;
                _tmpPrice = _cursor.getFloat(_cursorIndexOfPrice);
                final String _tmpPublishData;
                if (_cursor.isNull(_cursorIndexOfPublishData)) {
                    _tmpPublishData = null;
                } else {
                    _tmpPublishData = _cursor.getString(_cursorIndexOfPublishData);
                }
                _item = new Book(_tmpName,_tmpAuthor,_tmpPrice,_tmpPublishData);
                final int _tmpBookId;
                _tmpBookId = _cursor.getInt(_cursorIndexOfBookId);
                _item.setBookId(_tmpBookId);
                _result.add(_item);
            }
            return _result;
        } finally {
            _cursor.close();
            _statement.release();
        }
    }
    
    @Override
    public List<Book2> queryBookWithPartFiled() {
        final String _sql = "select name,author from Book";
        final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
        __db.assertNotSuspendingTransaction();
        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
        try {
            final int _cursorIndexOfName = 0;
            final int _cursorIndexOfAuthor = 1;
            final List<Book2> _result = new ArrayList<Book2>(_cursor.getCount());
            while(_cursor.moveToNext()) {
                final Book2 _item;
                final String _tmpName;
                if (_cursor.isNull(_cursorIndexOfName)) {
                    _tmpName = null;
                } else {
                    _tmpName = _cursor.getString(_cursorIndexOfName);
                }
                final String _tmpAuthor;
                if (_cursor.isNull(_cursorIndexOfAuthor)) {
                    _tmpAuthor = null;
                } else {
                    _tmpAuthor = _cursor.getString(_cursorIndexOfAuthor);
                }
                _item = new Book2(_tmpName,_tmpAuthor);
                _result.add(_item);
            }
            return _result;
        } finally {
            _cursor.close();
            _statement.release();
        }
    }
    
    public static List<Class<?>> getRequiredConverters() {
        return Collections.emptyList();
    }
}

当用@DataBase标注AppDataBase类,会在build/generated/source/kapt/debug/包名/下生成AppDataBase_impl.java。该类主要进行了表的创建工作。

package cn.zhangmushui.room;

import androidx.annotation.NonNull;
import androidx.room.DatabaseConfiguration;
import androidx.room.InvalidationTracker;
import androidx.room.RoomOpenHelper;
import androidx.room.RoomOpenHelper.Delegate;
import androidx.room.RoomOpenHelper.ValidationResult;
import androidx.room.migration.AutoMigrationSpec;
import androidx.room.migration.Migration;
import androidx.room.util.DBUtil;
import androidx.room.util.TableInfo;
import androidx.room.util.TableInfo.Column;
import androidx.room.util.TableInfo.ForeignKey;
import androidx.room.util.TableInfo.Index;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Callback;
import androidx.sqlite.db.SupportSQLiteOpenHelper.Configuration;
import java.lang.Class;
import java.lang.Override;
import java.lang.String;
import java.lang.SuppressWarnings;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@SuppressWarnings({"unchecked", "deprecation"})
public final class AppDataBase_Impl extends AppDataBase {
  private volatile BookDao _bookDao;

  @Override
  protected SupportSQLiteOpenHelper createOpenHelper(DatabaseConfiguration configuration) {
    final SupportSQLiteOpenHelper.Callback _openCallback = new RoomOpenHelper(configuration, new RoomOpenHelper.Delegate(2) {
      @Override
      public void createAllTables(SupportSQLiteDatabase _db) {
        _db.execSQL("CREATE TABLE IF NOT EXISTS `Book` (`name` TEXT NOT NULL, `author` TEXT NOT NULL, `price` REAL NOT NULL, `data` TEXT NOT NULL, `bookId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL)");
        _db.execSQL("CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)");
        _db.execSQL("INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '049deb639df8f34cc670d599e5105986')");
      }

      @Override
      public void dropAllTables(SupportSQLiteDatabase _db) {
        _db.execSQL("DROP TABLE IF EXISTS `Book`");
        if (mCallbacks != null) {
          for (int _i = 0, _size = mCallbacks.size(); _i < _size; _i++) {
            mCallbacks.get(_i).onDestructiveMigration(_db);
          }
        }
      }

      @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);
          }
        }
      }

      @Override
      public void onPreMigrate(SupportSQLiteDatabase _db) {
        DBUtil.dropFtsSyncTriggers(_db);
      }

      @Override
      public void onPostMigrate(SupportSQLiteDatabase _db) {
      }

      @Override
      protected RoomOpenHelper.ValidationResult onValidateSchema(SupportSQLiteDatabase _db) {
        final HashMap<String, TableInfo.Column> _columnsBook = new HashMap<String, TableInfo.Column>(5);
        _columnsBook.put("name", new TableInfo.Column("name", "TEXT", true, 0, null, TableInfo.CREATED_FROM_ENTITY));
        _columnsBook.put("author", new TableInfo.Column("author", "TEXT", true, 0, null, TableInfo.CREATED_FROM_ENTITY));
        _columnsBook.put("price", new TableInfo.Column("price", "REAL", true, 0, null, TableInfo.CREATED_FROM_ENTITY));
        _columnsBook.put("data", new TableInfo.Column("data", "TEXT", true, 0, null, TableInfo.CREATED_FROM_ENTITY));
        _columnsBook.put("bookId", new TableInfo.Column("bookId", "INTEGER", true, 1, null, TableInfo.CREATED_FROM_ENTITY));
        final HashSet<TableInfo.ForeignKey> _foreignKeysBook = new HashSet<TableInfo.ForeignKey>(0);
        final HashSet<TableInfo.Index> _indicesBook = new HashSet<TableInfo.Index>(0);
        final TableInfo _infoBook = new TableInfo("Book", _columnsBook, _foreignKeysBook, _indicesBook);
        final TableInfo _existingBook = TableInfo.read(_db, "Book");
        if (! _infoBook.equals(_existingBook)) {
          return new RoomOpenHelper.ValidationResult(false, "Book(cn.zhangmushui.room.Book).\n"
                  + " Expected:\n" + _infoBook + "\n"
                  + " Found:\n" + _existingBook);
        }
        return new RoomOpenHelper.ValidationResult(true, null);
      }
    }, "049deb639df8f34cc670d599e5105986", "4598151ad10511f4531db7d976d441f6");
    final SupportSQLiteOpenHelper.Configuration _sqliteConfig = SupportSQLiteOpenHelper.Configuration.builder(configuration.context)
        .name(configuration.name)
        .callback(_openCallback)
        .build();
    final SupportSQLiteOpenHelper _helper = configuration.sqliteOpenHelperFactory.create(_sqliteConfig);
    return _helper;
  }

  @Override
  protected InvalidationTracker createInvalidationTracker() {
    final HashMap<String, String> _shadowTablesMap = new HashMap<String, String>(0);
    HashMap<String, Set<String>> _viewTables = new HashMap<String, Set<String>>(0);
    return new InvalidationTracker(this, _shadowTablesMap, _viewTables, "Book");
  }

  @Override
  public void clearAllTables() {
    super.assertNotMainThread();
    final SupportSQLiteDatabase _db = super.getOpenHelper().getWritableDatabase();
    try {
      super.beginTransaction();
      _db.execSQL("DELETE FROM `Book`");
      super.setTransactionSuccessful();
    } finally {
      super.endTransaction();
      _db.query("PRAGMA wal_checkpoint(FULL)").close();
      if (!_db.inTransaction()) {
        _db.execSQL("VACUUM");
      }
    }
  }

  @Override
  protected Map<Class<?>, List<Class<?>>> getRequiredTypeConverters() {
    final HashMap<Class<?>, List<Class<?>>> _typeConvertersMap = new HashMap<Class<?>, List<Class<?>>>();
    _typeConvertersMap.put(BookDao.class, BookDao_Impl.getRequiredConverters());
    return _typeConvertersMap;
  }

  @Override
  public Set<Class<? extends AutoMigrationSpec>> getRequiredAutoMigrationSpecs() {
    final HashSet<Class<? extends AutoMigrationSpec>> _autoMigrationSpecsSet = new HashSet<Class<? extends AutoMigrationSpec>>();
    return _autoMigrationSpecsSet;
  }

  @Override
  public List<Migration> getAutoMigrations(
      @NonNull Map<Class<? extends AutoMigrationSpec>, AutoMigrationSpec> autoMigrationSpecsMap) {
    return Arrays.asList();
  }

  @Override
  public BookDao bookDao() {
    if (_bookDao != null) {
      return _bookDao;
    } else {
      synchronized(this) {
        if(_bookDao == null) {
          _bookDao = new BookDao_Impl(this);
        }
        return _bookDao;
      }
    }
  }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容