其实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 实体定义数据 等,进行更复杂的配置和使用。
本篇文章就到这里结束了。已经可以满足基本的开发持久化存储需要了。
如果后续还需要完善新的定制化方法,我们会开新的文章,并统一做成专栏,便于我后续回来自省。
五、参考:
- Room使用详解及常用数据库对比 – 对比一下数据库性能之类的,可以给大家决定是否替换权衡,做个简单参考