Room 在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。
处理大量结构化数据的应用可极大地受益于在本地保留这些数据。最常见的用例是缓存相关数据。这样,当设备无法访问网络时,用户仍可在离线状态下浏览相应内容。设备重新连接到网络后,用户发起的所有内容更改都会同步到服务器。
由于 Room 负责处理这些问题,因此建议使用 Room(而不是 SQLite)
Room添加依赖如下:
implementation "androidx.room:room-runtime:$room_version"annotationProcessor "androidx.room:room-compiler:$room_version" // Kotlin使用kaptimplementation "androidx.room:room-ktx:$room_version" // Room的kotlin扩展implementation "androidx.room:room-rxjava2:$room_version"// Room的RxJava扩展
Room的架构由以下(注解)组成:
数据库(@DataBase)
:包含数据库持有者,并作为应用已保留的持久关系型数据的底层连接的主要接入点。使用 @Database 注释的类应满足以下条件:
- 是扩展 RoomDatabase 的抽象类。
- 在注释中添加与数据库关联的实体列表。
- 包含具有 0 个参数且返回使用 @Dao 注释的类的抽象方法。
在运行时,您可以通过调用 Room.databaseBuilder() 或 Room.inMemoryDatabaseBuilder() 获取 Database 的实例。实体(@Entity)
:表示数据库中的表。- DAO(@Dao):包含用于访问数据库的方法。
下面以官方文档的示意图来介绍
以下为官方示例:
User
@Entitydata class User(@PrimaryKey val uid: Int,@ColumnInfo(name = "first_name") val firstName: String?,@ColumnInfo(name = "last_name") val lastName: String?)
创建了User表,@Entity表示为表Class,@PrimaryKey表示该属性为主键,@ColumnInfo表示当前行,name指明行名。
UserDao
@Daointerface UserDao {
@Query("SELECT * FROM user")fun getAll(): List<User>@Query("SELECT * FROM user WHERE uid IN (:userIds)")fun loadAllByIds(userIds: IntArray): List<User>@Query("SELECT * FROM user WHERE first_name LIKE :first AND " +"last_name LIKE :last LIMIT 1")fun findByName(first: String, last: String): User@Insertfun insertAll(vararg users: User)@Deletefun delete(user: User)}
@Dao注解表示对外暴露的数据库接口。
接口中函数的注解@Query执行查询操作,value写SQL 查询语句,SQL语法字符串采用大写,变量采用小写,”:“引用函数的参数,返回值根据结果而定,可返回LiveData或者配合RxJava扩展返回可订阅对象(Flowable, Maybe, Single, Completable),后面的@Insert,@Delete,@Update都一样。
AppDatabase
@Database(entities = arrayOf(User::class), version = 1)abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao}
@Database表示数据库,里面的entities参数可指定表的Class,version指定版本号,等等,其他的可自行查看源码。
抽象类内部则是返回Dao的抽象方法。
最后创建数据库即可。
val db = Room.databaseBuilder(applicationContext,AppDatabase::class.java, "database-name").build()
以上编译完成后,会生成UserDao_Impl文件,顾名思义便是UserDao接口的实现。
当然这只是最简单的用法,你也可以结合LiveData和Rxjava实现响应式的获取数据。
配合LiveData
@Query("SELECT * FROM user WHERE uid IN (:userIds)")fun loadAllByIds(userIds: IntArray): LiveData<List<User>>
当数据库初始化或数据发生改变的时候会响应上面的方法,剩下的就是LiveData相关了,具体的操作可以了解下LiveData的使用方式。
配合Rxjava
与Rxjava配合比LiveData稍麻烦,但也无妨。
引入依赖:
implementation “androidx.room:room-rxjava2:$room_version”// Room的RxJava扩展
然后更改返回结果的类型:
@Query("SELECT * FROM user WHERE uid IN (:userIds)")fun loadAllByIds(userIds: IntArray): Flowable<List<User>>
当然不只有Flowable一个返回类型,有以下几个:
- Flowable:
- 1.当所查询的表中无改值时或查询语句返回空时Flowable将不会发射数据,
onNext
和onError
也不会回调 - 2.当查询到数据时回调
onNext
- 3.当数据库初始化时或者数据发生改变时自动发射数据回调
onNext
- 1.当所查询的表中无改值时或查询语句返回空时Flowable将不会发射数据,
- Maybe:
- 1.当查询结果返回空时回调
onComplete
- 2.当有结果时回调
onSuccess
和onComplete
- 3.在
onComplete
回调后如果数据发生更新,将不会响应
- 1.当查询结果返回空时回调
- Single
- 1.当查询结果为空时返回回调
onError(EmptyResultSetException.class)
- 2.当有结果时回调
onSuccess
- 3.在
onComplete
回调后如果数据发生更新,将不会响应
- 1.当查询结果为空时返回回调
所有根据实际的场景选择合适的方法才是正确的使用方式。