当前栏目
实战 | 在 Room 中使用 Flow
△ Room 中对 Flow 的支持
Jetpack Room 对协程的支持越来越丰富: Room 2.1 版本增加了对协程的支持,并加入了一次性 (one-shot) 的读写操作,Room 2.2 我们通过 Flow 为读操作加入了可观察性,当数据库中的数据有变化时它可以使您收到通知。
△ Room 支持异步 query 操作
Flow 实战
假设我们有一个记录小狗信息的数据库,它的 name 字段是主键 (primary key),所以在数据库中不可能同时有两个 name 字段相同的数据,也就是每只小狗都是唯一的。
@Entity
data class Dog (
@PrimaryKey val name: String,
val cuteness: Int,
val barkingVolume: Int
)
为了从数据中获取一个包含所有小狗信息的总表,我们在 DAO 中编写如下 query 语句:
@Query("SELECT * FROM Dog")
fun getAllDogs(): List<Dog>
因为小狗的叫声,也就是字段 barkingVolume 会随着时间变化,并且我们想确保 UI 展示的内容是最新的。因此我们希望,当数据库中的数据有变化时,可以通知到我们: 比如新增,删除,或者是更新了数据。
为了实现这个功能,我们通过更新 query 操作返回一个 Flow 对象。
@Query("SELECT * FROM Dog")
fun getAllDogs(): Flow<List<Dog>>
就像这样,每当数据库中的数据有更新时,会重新派发存有小狗信息的总表。例如,假设我们的数据库中存有如下数据:
(Frida, 11, 3)
(Bandit, 12, 5)
第一次调用 getAllDogs 时 Flow 派发的数据如下:
[(Frida, 11, 3), (Bandit, 12, 5)]
如果小狗 Bandit 比较兴奋,那它的叫声也会变大,也就是字段 barkingVolume 更新为 6: (Bandit,12,6),这时候 Flow 会重新派发最新数据,所以整个列表被更新为:
[(Frida, 11, 3), (Bandit, 12, 6)]
现在我们来看一下获取单只小狗详细信息的操作,为了能够实时地获取小狗的最新数据,我们返回 Flow:
@Query("SELECT * FROM Dog WHERE name = :name")
fun getDog(name: String): Flow<Dog>
如果我们调用 getDog("Frida"),Flow 会返回一个对象: (Frida, 11, 3)。
只要是数据库中的任意一个数据有更新,无论是哪一行数据的更改,那就重新执行 query 操作并再次派发 Flow,因此当小狗 Frida 有更新时我们会收到最新的数据。同样道理,如果一个不相关的数据,比如小狗 Bandit 有更新时我们的 Flow 也会被派发,而且会收到与之前相同的数据: (Frida, 11, 3)。
这是因为 SQLite 数据库的内容更新通知功能是以表 (Table) 数据为单位,而不是以行 (Row) 数据为单位,因此只要是表中的数据有更新,它就触发内容更新通知。Room 不知道表中有更新的数据是哪一个,因此它会重新触发 DAO 中定义的 query 操作。您可以使用 Flow 的操作符,比如 distinctUntilChanged 来确保只有在当您关心的数据有更新时才会收到通知。
@Dao
abstract class DoggosDao {
@Query("SELECT * FROM Dog WHERE name = :name")
abstract fun getDog(name: String): Flow<Dog>
fun getDogDistinctUntilChanged(name:String) =
getDog(name).distinctUntilChanged()
}
推荐您通过 Flow 进行可观察的读操作,以获取数据库中数据更新的通知!您可以在您的整个应用中使用协程 (Coroutine) 和 Flow,而且还可使用 Jetpack 库中支持的其他协程功能,比如: 生命周期感知型协程范围 (lifecycle-aware coroutine scopes) 、挂起生命周期感知型协程 (suspend lifecycle-aware coroutines),也包括 Flow 转 LiveData 的操作。
查看更多使用 Flow 的案例,可参考我们之前发布的一篇基于 Android 开发者峰会应用的最佳实践 的文章。
相关文章
- Fabric.js 使用纯色遮挡画布(前景色)
- Tensorflow2.X中使用自编码器图像重构实战---文末送书
- 实战模拟│使用多进程教你下载 m3u8 加密或非加密视频「建议收藏」
- MyBatis-Plus 基础+进阶+实战 之 灵活使用lambda 构造sql 条件
- 二、基本类型及函数使用《2022 solidity8.+ 版本教程到实战》
- 100个Python实战项目(十一)如何使用 Python 获取电话号码信息?
- springcloud实战:使用代码生成器生成代码操作数据库
- node.js中间件multer的使用
- 【深入浅出Java原理及实战】「源码分析系列」深入分析反射功能基础使用和原理
- UniColor - 使用 Transformer 进行多模态着色的统一框架 !论文速递2022.9.28!
- 一篇文章教你正确解锁 代理ip 的使用方式,包含两个实战案例
- 实战:第十九章:存入Long类型对象,在代码中使用Long类型接收,结果报类型转换错误
- 使用 NineData 高效编写 SQL
- ONLYOFFICE中如何使用chatGPT
- 使用Linux ASMCMD管理Oracle Automatic Storage Management(linuxasmcmd)
- 研究人员在新冠大流行期间追踪COVID-19治疗药物的使用情况
- Linux SVN实战:开启新的编程世界(linuxsvn使用)
- Linux禁止使用防火墙保护系统(linux禁止防火墙)
- 使用情况Linux下轻松查看CPU使用情况(linux获取cpu)
- MySQL中的变量使用及其实现原理(mysql 变量)
- Oracle的共享临时表使用简洁明了(oracle共享临时表)
- MySQL中查询BAT工具的使用(bat mysql 查询)
- 使用Redis实现分布式缓存的最佳实践(分布式缓存redis实战)
- 这才是使用数据降维&可视化工具 HyperTools 的正确姿势! | Kaggle 实战教程