Room的初衷
提起SQLite,作为Android开发者还是比较幸福的的,Android核心框架已为处理SQL提供了相当大的支持,API也非常强大,省起来很大的力气。但是其模板化处理方式,导致开发者花费大量的时间和精力去维护数据库:
- 在编译时,没有对原始SQL查询语句验证。随着表结构的更改,需要手动更新SQL查询语句。这个过程不仅耗时耗精力,而且很容易出错。
- 需要使用大量的样板代码执行SQL操作和Java数据对象之间的转换。
正因为这些原因,一批大神造轮子,开源了很多优秀的开源框架,比如GreenDao、OrmLite、Active Android等等,给我们带来了十分的便利。
这里给大家推荐另外一个开源框架 - Room,其作者是Android的爹Google。既然是Google出品,我想有必要学习一下。
Room给我们带来了什么样的惊喜呢?
- 避免了样板间似的代码块。
- 能轻松的将SQLite表数据转换为Java对象
- Room提供了编译SQLite语句时检查,避免了SQL语句在执行时,才发现错误
- 可以返回RxJava的Flowable和LiveData的可观察实例,对SQLite的异步操作提供强力支持。
Gradle配置
在buildl.gradle里面添加依赖即可:
- compile “android.arch.persistence.room:runtime:1.0.0-alpha1”
- annotationProcessor “android.arch.persistence.room:compiler:1.0.0-alpha1”
Room对RxJava 2是完美支持, 如果习惯了RxJava异步操作的,可以添加RxJava支持库:
- compile “android.arch.persistence.room:rxjava2:1.0.0-alpha1”
Room的三大组成部分
- Database(数据库):使用此组件创建数据库Holder。
- 通过注解实体类定义表结构,该实体类的实例即为数据库中的数据访问对象(在Dao内操作)。
- 它是链接SQL底层的主要接入点。
- 注解的类必须是继承于RoomDatabase的抽象类
- 在运行时,可以通过调用Room.databaseBuilder()或Room.inMemoryDatabaseBuilder()获取其实例
Entity(实体类):该组件表示持有一个表的字段(即数据库一行的数据)的实体类。
- 对于每个实体,创建一个数据库表来保存它们。
- 必须通过Database类中的Entity数组引用实体类
- 实体类的每个字段都会保存数据库的表中。如果不想保存某字段,该字段需使用@Ignore注解
如果Dao类可以访问每个持久化的字段(即表中的字段),实体可以有一个空构造函数。当然,该实体类还可以有一个构造函数,其参数应包含与实体中的字段相匹配的类型和名称。Room可以使用含有全部字段或者部分字段的构造函数,例如只含有部分字段的构造函数??????
DAO(抽象类/接口):该组件表示作为数据访问对象(DAO即为Data Access Object的简写)的类或者接口。
- DAO是Room的主要组件,负责定义访问数据库的方法。
- 该抽象类或接口使用@Database注解,同时必须含有一个无参数的抽象方法,并返回@Dao注解的实际操作类。
- 在编译时,Room创建这个抽象类或接口的实现。
注意:通过使用DAO类访问数据库,而不是使用查询构建器或直接查询,可以将数据库体系结构的不同组件分离。另外,在测试应用程序时,DAO可以轻松的模拟数据库访问。
Room与应用程序的架构体系
简单使用
现在已经对Room库有了初步的认识,下面我们来看看Room库在应用程序中,怎么应用的呢?
创建实体类-UserEntity,使用@Entity注解,将其作为数据库中的一个表的实体
@Entity(tableName = "user") data class UserEntity (@PrimaryKey @ColumnInfo(name = "id")val id: Int, @ColumnInfo(name = "name")val name: String, @ColumnInfo(name = "is_brrowed")val isBrrowed: Int)
声明抽象类AppDatabase,继承于RoomDatabase,该类使用@Database注解,用于为应用程序创建一个数据库
@Database(entities = arrayOf(UserEntity::class), version = 1) abstract class AppDatabase: RoomDatabase() { }
请注意:- 在Kotlin中,entities注解参数为vararg参数传递时,必须将参数的显示的的声明为arrayOf()。
- 在编译时,由Room库对AppDatabase实现,我们不需多做处理。
创建数据库访问对象(DAO), 用于访问数据库
@Dao interface UserDao { // 向表中插入一系列 @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertUser(vararg user: UserEntity) @Insert fun insertUser(users: List<UserEntity>) *** }
在AppDatabase引用UserDao,就是在AppDatabase中声明一个抽象方法,返回UserDao实例。
@Database(entities = arrayOf(UserEntity::class), version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
创建数据库,像数据库添加数据后,并查询。
class RoomActivity : BaseActivity() { *** @SuppressLint("StaticFieldLeak") override fun setListener() { acb_create.setOnClickListener { doAsync { applicationContext.deleteDatabase(DATABASE_NAME) mDataBase = Room.databaseBuilder(applicationContext, AppDatabase::class.java, DATABASE_NAME).build() } } acb_insert.setOnClickListener { doAsync { val users: MutableList<UserEntity> = mutableListOf() (0..10).mapTo(users) { val user = UserEntity(id, "Test - it", id % 2) id++ user } mDataBase?.beginTransaction() try { mDataBase?.userDao()?.insertUser(users) mDataBase?.setTransactionSuccessful() } finally { mDataBase?.endTransaction() } } } *** acb_query.s