Android Jetpack 学习之旅--> Room 的使用
Posted Kevin-Dev
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack 学习之旅--> Room 的使用相关的知识,希望对你有一定的参考价值。
我们在日常的工作中,免不了和数据打交道,因此,存储数据便是一项很重要的工作,在此之前,我使用过 GreenDao、DBFlow 等优秀的 ORM 数据库框架,但是,这些框架都不是谷歌官方的,现在,我们有了谷歌官方的 Room 数据库框架,看看它能够给我们带来什么?
介绍
官网介绍:
The Room persistence library provides an abstraction layer over SQLite to allow for more robust database access while harnessing the full power of SQLite.
简单来说:Room 是一个基于 SQLite 的强大数据库框架。
优点:
- 使用编译时注解,能够对
@Query
和@Entity
里面的SQL
语句等进行验证。 - 与
SQL
语句的使用更加贴近,能够降低学习成本。 - 对
RxJava 2
的支持(大部分都android
数据库框架都支持),对LiveData
的支持。 @Embedded
能够减少表的创建。
学习资料:
实战之旅
1. 在 app/build.gradle 添加:
apply plugin: 'kotlin-kapt'
dependencies
// room
implementation "androidx.room:room-runtime:$rootProject.roomVersion"
implementation "androidx.room:room-ktx:$rootProject.roomVersion"
kapt "androidx.room:room-compiler:$rootProject.roomVersion"
androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"
项目下的 build.gradle 添加:
ext
roomVersion = '2.1.0-alpha06'
2. 创建表(实体)
- 用户表:
/**
* 用户表
*/
@Entity(tableName = "user")
data class User(
@ColumnInfo(name = "user_account") val account: String // 账号
, @ColumnInfo(name = "user_pwd") val pwd: String // 密码
, @ColumnInfo(name = "user_name") val name: String
, @Embedded val address: Address // 地址
, @Ignore val state: Int // 状态只是临时用,所以不需要存储在数据库中
)
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Long = 0
- 收藏记录表:
/**
* 喜欢的球鞋
*/
@Entity(
tableName = "fav_shoe"
, foreignKeys = [ForeignKey(entity = Shoe::class, parentColumns = ["id"], childColumns = ["shoe_id"])
, ForeignKey(entity = User::class, parentColumns = ["id"], childColumns = ["user_id"])
],indices = [Index("shoe_id")]
)
data class FavouriteShoe(
@ColumnInfo(name = "shoe_id") val shoeId: Long // 外键 鞋子的id
, @ColumnInfo(name = "user_id") val userId: Long // 外键 用户的id
, @ColumnInfo(name = "fav_date") val date: Date // 创建日期
)
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Long = 0
- 鞋表:
/**
* 鞋表
*/
@Entity(tableName = "shoe")
data class Shoe(
@ColumnInfo(name = "shoe_name") val name: String // 鞋名
, @ColumnInfo(name = "shoe_description") val description: String// 描述
, @ColumnInfo(name = "shoe_price") val price: Float // 价格
, @ColumnInfo(name = "shoe_brand") val brand: String // 品牌
, @ColumnInfo(name = "shoe_imgUrl") val imageUrl: String // 图片地址
)
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var id: Long = 0
- 注解解释:
@Entity
声明这是一个表(实体),主要参数:tableName
-表名、foreignKeys
-外键、indices
-索引。
@ColumnInfo
主要用来修改在数据库中的字段名。
@PrimaryKey
声明该字段主键并可以声明是否自动创建。
@Ignore
声明某个字段只是临时用,不存储在数据库中。
@Embedded
用于嵌套,里面的字段同样会存储在数据库中。
3. 创建 Dao
数据的增删查改。如果想声明一个 Dao
,只要在抽象类或者接口加一个 @Dao
注解就行。
- 增
@Insert
注解声明当前的方法为新增的方法,并且可以设置当新增冲突的时候处理的方法。
@Dao
interface ShoeDao
// 省略...
// 增加一双鞋子
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertShoe(shoe: Shoe)
// 增加多双鞋子
// 除了List之外,也可以使用数组
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertShoes(shoes: List<Shoe>)
- 删
@Delete
注解声明当前的方法是一个删除方法。
@Dao
interface ShoeDao
// 省略...
// 删除一双鞋子
@Delete
fun deleteShoe(shoe: Shoe)
// 删除多个鞋子
// 参数也可以使用数组
@Delete
fun deleteShoes(shoes:List<Shoe>)
- 改
@Update
注解声明当前方法是一个更新方法
@Dao
interface ShoeDao
// 省略...
// 更新一双鞋
@Update
fun updateShoe(shoe:Shoe)
// 更新多双鞋
// 参数也可以是集合
@Update
fun updateShoes(shoes:Array<Shoe>)
- 查
Room
的查很接近原生的SQL
语句。@Query
注解不仅可以声明这是一个查询语句,也可以用来删除和修改,不可以用来新增。
@Dao
interface ShoeDao
// 查询一个
@Query("SELECT * FROM shoe WHERE id=:id")
fun findShoeById(id: Long): Shoe?
// 查询多个 通过品牌查询多款鞋
@Query("SELECT * FROM shoe WHERE shoe_brand=:brand")
fun findShoesByBrand(brand: String): List<Shoe>
// 模糊查询 排序 同名鞋名查询鞋
@Query("SELECT * FROM shoe WHERE shoe_name LIKE :name ORDER BY shoe_brand ASC")
fun findShoesByName(name:String):List<Shoe>
// 配合LiveData 返回所有的鞋子
@Query("SELECT * FROM shoe")
fun getAllShoesLD(): LiveData<List<Shoe>>
// 配合LiveData 通过Id查询单款鞋子
@Query("SELECT * FROM shoe WHERE id=:id")
fun findShoeByIdLD(id: Long): LiveData<Shoe>
// 配合RxJava 通过Id查询单款鞋子
@Query("SELECT * FROM shoe WHERE id=:id")
fun findShoeByIdRx(id: Long): Flowable<Shoe>
// 省略...
- 复合查询
以LiveData
为例
@Dao
interface ShoeDao
// 省略...
// 根据收藏结合 查询用户喜欢的鞋的集合 内联查询
@Query(
"SELECT shoe.id,shoe.shoe_name,shoe.shoe_description,shoe.shoe_price,shoe.shoe_brand,shoe.shoe_imgUrl " +
"FROM shoe " +
"INNER JOIN fav_shoe ON fav_shoe.shoe_id = shoe.id " +
"WHERE fav_shoe.user_id = :userId"
)
fun findShoesByUserId(userId: Long): LiveData<List<Shoe>>
4. 创建数据库
创建一个数据库对象是一件非常消耗资源,使用单例可以避免过多的资源消耗。
/**
* 数据库文件
*/
@Database(entities = [User::class,Shoe::class,FavouriteShoe::class],version = 1,exportSchema = false)
abstract class AppDataBase:RoomDatabase()
// 得到UserDao
abstract fun userDao():UserDao
// 得到ShoeDao
abstract fun shoeDao():ShoeDao
// 得到FavouriteShoeDao
abstract fun favouriteShoeDao():FavouriteShoeDao
companion object
@Volatile
private var instance:AppDataBase? = null
fun getInstance(context:Context):AppDataBase
return instance?: synchronized(this)
instance?:buildDataBase(context)
.also
instance = it
private fun buildDataBase(context: Context):AppDataBase
return Room
.databaseBuilder(context,AppDataBase::class.java,"jetPackDemo-database")
.addCallback(object :RoomDatabase.Callback()
override fun onCreate(db: SupportSQLiteDatabase)
super.onCreate(db)
// 读取鞋的集合
val request = OneTimeWorkRequestBuilder<ShoeWorker>().build()
WorkManager.getInstance(context).enqueue(request)
)
.build()
@Database
注解声明当前是一个数据库文件,注解中entities
变量声明数据库中的表(实体),以及其他的例如版本等变量。同时,获取的Dao
也必须在数据库类中。完成之后,点击build
目录下的make project
,系统就会自动帮我创建AppDataBase
和xxxDao
的实现类。
5. 简要封装
这里有必要提醒一下,在不使用 LiveData 和 RxJava 的前提下,Room 的操作是不可以放在主线程中的。
/**
* 用户处理仓库
*/
class UserRepository private constructor(private val userDao: UserDao)
//...
/**
* 登录用户 本地数据库的查询
*/
fun login(account: String, pwd: String):LiveData<User?>
= userDao.login(account,pwd)
/**
* 注册一个用户 本地数据库的新增
*/
suspend fun register(email: String, account: String, pwd: String):Long
return withContext(IO)
userDao.insertUser(User(account, pwd, email))
companion object
@Volatile
private var instance: UserRepository? = null
fun getInstance(userDao: UserDao): UserRepository =
// ...
现在,你就可以愉快的操作本地数据库了。
参考文章:
《Android Room 框架学习》
关注我的视频号,每天都有优质视频教学推送。
微信扫一扫下方二维码即可关注:
以上是关于Android Jetpack 学习之旅--> Room 的使用的主要内容,如果未能解决你的问题,请参考以下文章
Android Jetpack 学习之旅--> Data Binding 的使用
Android Jetpack学习之旅--> Navigation 的使用
Android Jetpack 学习之旅--> ViewModel & LiveData 的使用
Android Jetpack 学习之旅--> Room 的使用