Jetpack:Room配合LiveData/Flow使用优化,Room+Flow使用原理解析。
系列文章目录
相关文章:
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使用原理解析。相关推荐
- Android Jetpack组件之 LiveData使用-源码
1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...
- Android Jetpack Components of LiveData 学习笔记
Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...
- Jetpack Room 使用及原理解析
深入学习 Jetpack 系列的 Android Architecture Components 中的一些列组件,记录一下学习过程,本文是 Room 的使用及原理解析,通过一个实际的例子,来体验 Ro ...
- jetpack compose原理解析
目录 jetpack compose原理解析 jetpack compse 声明式ui开发 原理分析 整体框架介绍 compose LayoutNode布局介绍 @Composeable注解实现细节 ...
- 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)
2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六) 中, 介绍了 ...
- 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...
- 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 ...
- 秋色园QBlog技术原理解析:性能优化篇:打印页面SQL,全局的SQL语句优化(十三)...
文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...
- 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及超级分库分散并发方案(十六)...
上节回顾: 上节 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五) 中, 介绍了 秋色园QBlog 在性能优化方面,从技术的优化手段,开始步入数据库设计优化,并从数据的 ...
- 【Kotlin 协程】Flow 异步流 ② ( 使用 Flow 异步流持续获取不同返回值 | Flow 异步流获取返回值方式与其它方式对比 | 在 Android 中使用 Flow 异步流下载文件 )
文章目录 一.使用 Flow 异步流持续获取不同返回值 二.Flow 异步流获取返回值方式与其它方式对比 三.在 Android 中 使用 Flow 异步流下载文件 一.使用 Flow 异步流持续获取 ...
最新文章
- Git 安装和使用教程(Windows)
- TIOBE 8 月榜单:Groovy 和 Objective-C 重返前二十
- 分辨率设置640*480
- 机器学习:林智仁libsvm 工具箱 在matlab下的应用总结
- 小程序引入的echarts过大如何解决_解决微信小程序引用echarts视图模糊的问题
- QT5 串口收发实例代码
- centos安装python3.7.0过程记录
- 38个Pandas实用技巧
- 把散乱的SQL赶出程序代码中
- Layer下拉框监听
- js 表格动态增加行通用函数
- jhipster使用简明教程
- C# 中文乱码,转成中文
- OSS接口获取的图片压缩大小 简单好用直接在src获取的地址后面拼接
- linux离线安装字体
- 中国Android应用商店汇总
- 推荐算法(一)——FM因式分解机
- 获取iPhone各个版本屏幕大小
- 战争磨盘十四:战争磨盘
- 小白知识之:画图软件中文字横横竖竖的奥秘
热门文章
- 西南地区首次大型“社区面基 Party”落幕,TiDB TechDay 下一站深圳见!
- c语言录制,C语言中如何录制屏幕
- 图像超分辨率:优化最近邻插值Super-Resolution by Predicting Offsets
- 信用评分模型详解(下)之 信用评分系统搭建
- OKR-Periods of Words
- 程序员的幽默你不懂:那些让你爆笑的程序员段子
- 史上最搞笑的程序员段子,有图有真相!
- 移动支付的发展优势有哪些?
- 前端性能优化工具waterfall
- python爬虫01-get请求,post请求,参数拼接,re正则解析,bs解析,xpath解析xml及html文件,requests进阶模拟登录,反盗链zhuanqu,代理