系列文章目录

相关文章:
Jetpack:Room超详细使用踩坑指南!
Jetpack:Room+kotlin协程? 事务问题分析,withTransaction API 详解.
Jetpack:Room使用报错FAQ


文章目录

  • 系列文章目录
  • 配合LiveData使用
  • 配合Flow使用
  • room+flow原理解析

配合LiveData使用

只需要Dao接口声明的方法返回类型需要用LiveData包装

    //Dao@Query("select * from $STUDENT_TABLE_NAME")suspend fun obtainStudentAll(): LiveData<List<StudentEntity>>//ViewModelfun obtainStudentAllUseLiveData() = dao.obtainStudentAll()

使用:onCreate里面订阅一次对应的LiveData。之后同一个数据库对象,就可以做到,一旦更新之后就可以里面通知到对应的订阅者了。伪代码:

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//liveDataviewModel.obtainStudentAllUseLiveData().observe(this@RoomDemoActivity, object : Observer<List<StudentEntity>> {override fun onChanged(t: List<StudentEntity>?) {//UI 显示 下面所有的增啥改查,导致表发生变化之后,这里会立即收到回调通知displayToTextView(t!!)}})}//数据库增删改查操作btnInsert.setOnClickListener {lifecycleScope.launch {viewModel.insertStudent(StudentEntity(0, "zxf", "18"))}}btnDelete.setOnClickListener {lifecycleScope.launch {viewModel.deleteStudent(StudentEntity(2, "delete", "99"))}}btnUpdate.setOnClickListener {lifecycleScope.launch {viewModel.updateStudent(StudentEntity(199, "update", "99"))}}

配合Flow使用

只需要Dao接口声明的方法返回的类型为Flow

    //flow@Query("select * from $STUDENT_TABLE_NAME")fun obtainStudentAll(): Flow<List<StudentEntity>>//viewModelfun obtainStudentAllUseFlow() = dao.obtainStudentAll()

使用:在onCreate里面collect一次对应的Flow,之后同一个数据库对象,就可以做到,一旦更新之后就可以里面通知flow的调用者了。伪代码如下:

    override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//直接拉取显示lifecycleScope.launch {//flowviewModel.obtainStudentAllUseFlow().collect {//UI 显示 下面所有的增啥改查,导致表发生变化之后,这里会立即收到回调通知displayToTextView(it)}}}//数据库增删改查操作btnInsert.setOnClickListener {lifecycleScope.launch {viewModel.insertStudent(StudentEntity(0, "zxf", "18"))}}btnDelete.setOnClickListener {lifecycleScope.launch {viewModel.deleteStudent(StudentEntity(2, "delete", "99"))}}btnUpdate.setOnClickListener {lifecycleScope.launch {viewModel.updateStudent(StudentEntity(199, "update", "99"))}}

room+flow原理解析

由于官方推荐kotlin,且在加上flow配合kotlin协程强大的性能。所以官方后期主推的就是flow,这里呢,就对room配合flow做一下原理解析
看一下,生成Dao的实现类查询对应的源码:

  public Flow<List<StudentEntity>> obtainStudentAll() {final String _sql = "select * from student";final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);return CoroutinesRoom.createFlow(__db, false, new String[]{"student"}, new Callable<List<StudentEntity>>() {@Overridepublic List<StudentEntity> call() throws Exception {...}});}

省略掉中间具体的查询的内容,看返回的具体是一个CoroutinesRoom.createFlow这个东西。那我们就具体找一下CoroutinesRoom.createFlow方法,最后在CoroutinesRoom.kt 里面找到了createFlow方法。createFlow完整源码如下:

 public fun <R> createFlow(db: RoomDatabase,inTransaction: Boolean,tableNames: Array<String>,callable: Callable<R>): Flow<@JvmSuppressWildcards R> = flow {// Observer channel receives signals from the invalidation tracker to emit queries.val observerChannel = Channel<Unit>(Channel.CONFLATED)val observer = object : InvalidationTracker.Observer(tableNames) {override fun onInvalidated(tables: MutableSet<String>) {observerChannel.offer(Unit)}}observerChannel.offer(Unit) // Initial signal to perform first query.val flowContext = coroutineContextval queryContext = coroutineContext[TransactionElement]?.transactionDispatcher?: if (inTransaction) db.transactionDispatcher else db.queryDispatcherwithContext(queryContext) {db.invalidationTracker.addObserver(observer)try {// Iterate until cancelled, transforming observer signals to query results to// be emitted to the flow.for (signal in observerChannel) {val result = callable.call()withContext(flowContext) { emit(result) }}} finally {db.invalidationTracker.removeObserver(observer)}}}}

大致先分析一下:使用channel,当channel并设置更新模式为CONFLATED(保留最新的值发送)。所以当每次往channel发送一个值得时候,下面得for循环就会迭代一次,调用一次emit,否则for循环挂起

在分析一下细节,什么时候会给channel发送值呢?我们看到,第一次调用该方法以及onInvalidated回调。第一次调用就不解释了;onInvalidated回调是什么呢?这个东西其实就是一个回调,当当前得数据库对象得表出现了变动(增删改),此时就会回调上来。此时往channel里面发送值。所以在首次调用createFlow以及表发生变动得时候channel会发送值。for循环执行一次。

看看for循环执行干了什么吧。首先看一下执行for循环得操作被调度到了异步得线程,不了解coroutineContext[TransactionElement]得可以参考:Jetpack:Room+kotlin协程? 事务问题分析,withTransaction API 详解.当for循环执行得时候,调用了callable.call(),这个是上面省略的表具体查询内容可以获取表格查询result,然后把线程切换到上面外面调用者自定义得线程把result emit出去

总结一下就是,当首次调用createFlow方法时,channel发送一次,然后执行一次查询,最后把结果emit出去。其他时候当表发生变动之后,执行一次查询,把结果emit发送出去。如何取消呢?只要把外层得协程取消掉就可以了

Jetpack:Room配合LiveData/Flow使用优化,Room+Flow使用原理解析。相关推荐

  1. Android Jetpack组件之 LiveData使用-源码

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  2. Android Jetpack Components of LiveData 学习笔记

    Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...

  3. Jetpack Room 使用及原理解析

    深入学习 Jetpack 系列的 Android Architecture Components 中的一些列组件,记录一下学习过程,本文是 Room 的使用及原理解析,通过一个实际的例子,来体验 Ro ...

  4. jetpack compose原理解析

    目录 jetpack compose原理解析 jetpack compse 声明式ui开发 原理分析 整体框架介绍 compose LayoutNode布局介绍 @Composeable注解实现细节 ...

  5. 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)

    2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六)  中, 介绍了 ...

  6. 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  7. 6、HIVE JDBC开发、UDF、体系结构、Thrift服务器、Driver、元数据库Metastore、数据库连接模式、单/多用户模式、远程服务模式、Hive技术原理解析、优化等(整理的笔记)

    目录: 5 HIVE开发 5.1 Hive JDBC开发 5.2 Hive UDF 6 Hive的体系结构 6.2 Thrift服务器 6.3 Driver 6.4 元数据库Metastore 6.5 ...

  8. 秋色园QBlog技术原理解析:性能优化篇:打印页面SQL,全局的SQL语句优化(十三)...

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  9. 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及超级分库分散并发方案(十六)...

    上节回顾: 上节 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五) 中, 介绍了 秋色园QBlog 在性能优化方面,从技术的优化手段,开始步入数据库设计优化,并从数据的 ...

  10. 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )

    文章目录 一.使用 Flow 异步流持续获取不同返回值 二.Flow 异步流获取返回值方式与其它方式对比 三.在 Android 中 使用 Flow 异步流下载文件 一.使用 Flow 异步流持续获取 ...

最新文章

  1. Git 安装和使用教程(Windows)
  2. TIOBE 8 月榜单:Groovy 和 Objective-C 重返前二十
  3. 分辨率设置640*480
  4. 机器学习:林智仁libsvm 工具箱 在matlab下的应用总结
  5. 小程序引入的echarts过大如何解决_解决微信小程序引用echarts视图模糊的问题
  6. QT5 串口收发实例代码
  7. centos安装python3.7.0过程记录
  8. 38个Pandas实用技巧
  9. 把散乱的SQL赶出程序代码中
  10. Layer下拉框监听
  11. js 表格动态增加行通用函数
  12. jhipster使用简明教程
  13. C# 中文乱码,转成中文
  14. OSS接口获取的图片压缩大小 简单好用直接在src获取的地址后面拼接
  15. linux离线安装字体
  16. 中国Android应用商店汇总
  17. 推荐算法(一)——FM因式分解机
  18. 获取iPhone各个版本屏幕大小
  19. 战争磨盘十四:战争磨盘
  20. 小白知识之:画图软件中文字横横竖竖的奥秘

热门文章

  1. 西南地区首次大型“社区面基 Party”落幕,TiDB TechDay 下一站深圳见!
  2. c语言录制,C语言中如何录制屏幕
  3. 图像超分辨率:优化最近邻插值Super-Resolution by Predicting Offsets
  4. 信用评分模型详解(下)之 信用评分系统搭建
  5. OKR-Periods of Words
  6. 程序员的幽默你不懂:那些让你爆笑的程序员段子
  7. 史上最搞笑的程序员段子,有图有真相!
  8. 移动支付的发展优势有哪些?
  9. 前端性能优化工具waterfall
  10. python爬虫01-get请求,post请求,参数拼接,re正则解析,bs解析,xpath解析xml及html文件,requests进阶模拟登录,反盗链zhuanqu,代理