jetpack开发实战——Room

其实Room依赖库的使用,相信各位大佬只要简单看一下官方文档有关Room的使用这一篇,很快就能融会贯通了。
但也正是因为比较简单,还没什么技术难度,浪费太多时间就不值得了,所以还没有尝试接入的小伙伴可以跟着我的文章一起更快了解一下。 我会把踩过的坑都简单记一下。

一、依赖库的使用

参考google官方文档的依赖

// 此实现对于kotlin有部分异常,踩坑的小伙伴往下看
dependencies {
    def room_version = "2.3.0"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
}
复制代码

为了后续应用的模块化结构,我们专门新建了一个android module,在子module中创建此依赖

a. 踩坑1 —— 子module的依赖属性

参考《文章:api与implementation的区别》 文章,回忆起了子mododule引用的异常问题。
需要将 implementation引用,改为 api引用,否则app 模块引用此子模块,会由于隐藏依赖,而无法访问相关类。

b. 踩坑2 —— 添加kapt,替换掉annotationProcessor

参考 stackoverflow上的相关问题——AppDatabase_Impl does not exist。 意识官方文档中提供的依赖方式,没有考虑kotlin的替换,需要将上面依赖的 annotationProcessor 替换为 kapt

另外,想要使用kapt,需要记得添加plugin

c. 最终实现

plugins {
    ...
    id 'kotlin-kapt'
}
...

dependencies {
    // 依赖 room lib
    def room_version = "2.3.0"
    api "androidx.room:room-runtime:$room_version"
    kapt  "androidx.room:room-compiler:$room_version"
}
复制代码

二、room相关实体类和database类的创建

Room已经对sql相关做了很好的封装,我们只要按照官方的文档正常使用,就不需要再自己去写繁琐的sql语句啦 具体的我们参考官方文档做下面的学习

首先,创建实体类Entity(我们先创建一个简单的Person类)

/**
 * @author Lucius Ren
 * @since 2021/9/1 21:33
 *
 * 数据库实体类  - person 保存每个人的基础信息
 */
@Entity(tableName = "person")
data class Person(
    @PrimaryKey val uidNum: Long,
    @ColumnInfo(name = "full_name") val fullName: String?,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?,
    @ColumnInfo(name = "sex") val sex: Int?,  // 0 for unknown, 1 for male, 2 for female
)
复制代码

接着,使用这个entity,创建相关Dao抽象接口(添加相关注解后,会自动生成具体的实现,这点感觉和greenDao方向差不多)

/**
 * @author Lucius Ren
 * @since 2021/9/1 21:42
 *
 * 对应Person表的Dao接口
 */
@Dao
interface PersonDao {
    @Query("SELECT * FROM person")
    fun getAll(): List<Person?>

    @Query("SELECT * FROM person WHERE uidNum IN (:userIds)")
    fun loadAllByIds(userIds: LongArray): List<Person?>

    @Query(
        "SELECT * FROM person WHERE first_name LIKE :first AND last_name LIKE :last LIMIT 1"
    )
    fun findByName(first: String, last: String): Person?

    @Query(
        "SELECT * FROM person WHERE full_name LIKE :fullName  LIMIT 1"
    )
    fun findByFullName(fullName: String): Person?

    @Insert
    fun insertAll(vararg users: Person)

    @Delete
    fun delete(user: Person)
}
复制代码

第三步,创建数据库Database抽象类(一样,使用注解,会生成具体的实现)

/**
 * @author Lucius Ren
 * @since 2021/9/1 21:33
 *
 * app使用的 数据库类
 */
@Database(entities = [Person::class], version = 1)
abstract class LuciusTowerDatabase: RoomDatabase() {
    abstract fun personDao(): PersonDao
}
复制代码

第四步,创建Util用来初始化数据库访问:

/**
 * @author Lucius Ren
 * @since 2021/9/1 22:04
 *
 * 使用单例模式访问数据库的util
 */
object LuciusTowerDatabaseUtil {
    const val DATABASE_NAME_LUCIUS_TOWER = "lucius-tower"

    var db: LuciusTowerDatabase? = null

    fun initDatabase(context: Context) {
        db = Room.databaseBuilder(
            context, LuciusTowerDatabase::class.java, DATABASE_NAME_LUCIUS_TOWER
        ).allowMainThreadQueries().build()
    }
}
复制代码

第五步,最后,在application的onCreate()中初始化数据库(如果你的应用不需要再一开始就初始化,可以考虑在需要的地方再调用)

override fun onCreate() {
    super.onCreate()
    // ...
    // 2. 初始化数据库
    LuciusTowerDatabaseUtil.initDatabase(this)
}
复制代码

三、自测数据库相关代码

相关的代码添加完成之后,加一个页面做一个简单自测。

// todo Lucius 删除debug代码
private fun insertPerson() {
    Log.d(TAG, "insertPerson")
    try {
        LuciusTowerDatabaseUtil.db?.personDao()?.insertAll(Person(123456L, "LuciusRen", "Lucius", "Ren", 1))
    } catch (e: Throwable) {
        Log.e(TAG, "insertPerson get error: $e")
    }
}

private fun checkPersonSex() {
    val person = LuciusTowerDatabaseUtil.db?.personDao()?.findByFullName("LuciusRen")
    val sex = person?.sex
    Log.d(TAG, "person = $person, sex = $sex")

    val peopleList = LuciusTowerDatabaseUtil.db?.personDao()?.getAll()
    Log.d(TAG, "personList = ${peopleList?.size},")
}
复制代码

通过测试按钮点击调用两个方法,得到如下日志:

2021-09-09 16:41:06.362 22470-22470/com.lucius.luciustower D/MainActivity: insertPerson

2021-09-09 16:41:09.365 22470-22470/com.lucius.luciustower D/MainActivity: person = Person(uidNum=123456, fullName=LuciusRen, firstName=Hongfei, lastName=Ren, sex=1), sex = 1
复制代码

四、小结

至此,我们的接入就基本完成了。
后续可以参考Goole官网的后续文章 —— 使用 Room 实体定义数据 等,进行更复杂的配置和使用。

本篇文章就到这里结束了。已经可以满足基本的开发持久化存储需要了。

如果后续还需要完善新的定制化方法,我们会开新的文章,并统一做成专栏,便于我后续回来自省。

五、参考:

  1. Room使用详解及常用数据库对比 – 对比一下数据库性能之类的,可以给大家决定是否替换权衡,做个简单参考
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享