Jetpack之Room的使用,结合Flow,Android自学资料

本文介绍了如何在Android中使用Jetpack的Room库管理搜索历史,结合Flow进行异步数据处理。从创建数据库和DAO,到获取、保存、删除历史记录,以及实现数据库迁移,详细阐述了每个步骤。同时强调了在单进程应用中避免多次实例化RoomDatabase的重要性,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@Database(entities = [History::class], version = 1)

abstract class HistoryDatabase : RoomDatabase() {

abstract fun historyDao(): HistoryDao

companion object {

private const val DATABASE_NAME = “history.db”

private lateinit var mPersonDatabase: HistoryDatabase

//注意:如果您的应用在单个进程中运行,在实例化 AppDatabase 对象时应遵循单例设计模式。

//每个 RoomDatabase 实例的成本相当高,而您几乎不需要在单个进程中访问多个实例

fun getInstance(context: Context): HistoryDatabase {

if (!this::mPersonDatabase.isInitialized) {

//创建的数据库的实例

mPersonDatabase = Room.databaseBuilder(

context.applicationContext,

HistoryDatabase::class.java,

DATABASE_NAME

).build()

}

return mPersonDatabase

}

}

}

  • 使用@Database注解声明

  • entities 数组,对应此数据库中的所有表

  • version 数据库版本号

注意:

如果您的应用在单个进程中运行,在实例化 AppDatabase 对象时应遵循单例设计模式。 每个 RoomDatabase

实例的成本相当高,而您几乎不需要在单个进程中访问多个实例。

使用

=============================================================

在需要的地方获取数据库

mHistoryDao = HistoryDatabase.getInstance(this).historyDao()

获取搜索历史

private fun getSearchHistory() {

MainScope().launch(Dispatchers.IO) {

mHistoryDao.getAll().collect {

withContext(Dispatchers.Main){

//更新ui

}

}

}

}

collectFlow获取数据的方式,并不是唯一方式,可以查看文档

为什么放在协程里面呢,因为数据库的操作是费时的,而协程可以轻松的指定线程,这样不阻塞UI线程。

查看Flow源码也发现,Flow是协程包下的

package kotlinx.coroutines.flow

以collect为例,也是被suspend 修饰的,既然支持挂起,那配合协程岂不美哉。

@InternalCoroutinesApi

public suspend fun collect(collector: FlowCollector)

保存搜索记录

private fun saveSearchHistory(text: String) {

MainScope().launch(Dispatchers.IO) {

mHistoryDao.insert(History(null, text, DateUtils.longToString(System.currentTimeMillis())))

}

}

清空本地历史

private fun cleanHistory() {

MainScope().launch(Dispatchers.IO) {

mHistoryDao.deleteAll()

}

}

作者:https://blog.youkuaiyun.com/yechaoa

数据库升级

================================================================

数据库升级是一个重要的操作,毕竟可能会造成数据丢失,也是很严重的问题。

Room通过Migration类来执行升级的操作,我们只要告诉Migration类改了什么就行,比如新增字段或表。

定义Migration类

/**

  • 数据库版本 1->2 t_history表格新增了updateTime列

*/

private val MIGRATION_1_2: Migration = object : Migration(1, 2) {

override fun migrate(database: SupportSQLiteDatabase) {

database.execSQL(“ALTER TABLE t_history ADD COLUMN updateTime String”)

}

}

/**

  • 数据库版本 2->3 新增label表

*/

private val MIGRATION_2_3: Migration = object : Migration(2, 3) {

override fun migrate(database: SupportSQLiteDatabase) {

database.execSQL(“CREATE TABLE IF NOT EXISTS t_label (id INTEGER PRIMARY KEY autoincrement, name TEXT)”)

}

}

Migration接收两个参数:

  • startVersion 旧版本

  • endVersion 新版本

通知数据库更新

mPersonDatabase = Room.databaseBuilder(

context.applicationContext,

HistoryDatabase::class.java,

DATABASE_NAME

).addMigrations(MIGRATION_1_2, MIGRATION_2_3)

.build()

完整代码

@Database(entities = [History::class, Label::class], version = 3)

abstract class HistoryDatabase : RoomDatabase() {

abstract fun historyDao(): HistoryDao

companion object {

private const val DATABASE_NAME = “history.db”

private lateinit var mPersonDatabase: HistoryDatabase

fun getInstance(context: Context): HistoryDatabase {

if (!this::mPersonDatabase.isInitialized) {

//创建的数据库的实例

mPersonDatabase = Room.databaseBuilder(

context.applicationContext,

HistoryDatabase::class.java,

DATABASE_NAME

).addMigrations(MIGRATION_1_2, MIGRATION_2_3)

.build()

}

return mPersonDatabase

}

/**

  • 数据库版本 1->2 t_history表格新增了updateTime列

*/

private val MIGRATION_1_2: Migration = object : Migration(1, 2) {

override fun migrate(database: SupportSQLiteDatabase) {

database.execSQL(“ALTER TABLE t_history ADD COLUMN updateTime String”)

}

}

/**

  • 数据库版本 2->3 新增label表

*/

private val MIGRATION_2_3: Migration = object : Migration(2, 3) {

override fun migrate(database: SupportSQLiteDatabase) {

database.execSQL(“CREATE TABLE IF NOT EXISTS t_label (id INTEGER PRIMARY KEY autoincrement, name TEXT)”)

}

}

}

}

注意:

@Database注解中版本号的更改,如果是新增表的话,entities参数里也要添加上。

建议升级操作顺序

修改版本号 -> 添加Migration -> 添加给databaseBuilder

配置编译器选项

==================================================================

Room 具有以下注解处理器选项:

  • room.schemaLocation:配置并启用将数据库架构导出到给定目录中的 JSON 文件的功能。如需了解详情,请参阅 Room 迁移。

  • room.incremental:启用 Gradle 增量注释处理器。

  • room.expandProjection:配置 Room 以重写查询,使其顶部星形投影在展开后仅包含 DAO 方法返回类型中定义的列。

android {

defaultConfig {

javaCompileOptions {

最后

总而言之,Android开发行业变化太快,作为技术人员就要保持终生学习的态度,让学习力成为核心竞争力,所谓“活到老学到老”只有不断的学习,不断的提升自己,才能跟紧行业的步伐,才能不被时代所淘汰。

在这里我分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。需要的朋友可以私信我【资料】或者 点这里 免费领取

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。 领取地址: Android学习PDF+架构视频+最新面试文档+源码笔记

[外链图片转存中…(img-DViv7TdU-1646557086747)]

[外链图片转存中…(img-7f8hPaZx-1646557086748)]

[外链图片转存中…(img-SZzsphvj-1646557086749)]

还有高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。 领取地址: Android学习PDF+架构视频+最新面试文档+源码笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值