Jetpack Compose数据库Room异步协程大坑记录
前言
俗话说得好,写代码一小时,修bug八小时。
今天在处理Room异步数据更新与StateFlow观察时出了一点bug,这里浅浅记录一下。
Jetpack Compose学习曲线还是陡啊……
问题描述
一个控件的回调函数中,使用rememberCoroutineScope
进行异步执行ViewModel中的从Room中删除指定Id记录
的函数,然后调用Compose中的allItems
变量(该变量值为ViewModel内RoomFlow<List<T>>
类型的数据流通过collectAsState
转化后的数据),判断allItems
集合是否为空。
测试时allItems仅有一条记录,当执行完删除代码后按理说allItems的isNotEmpty()应该为false,但测试后发现为true
代码结构如下:
1 | scope.launch { |
问题排查
一开始没注意是协程同步的问题,以为是Room异步Delete太慢,导致判断isNotEmpty()时还没删除完成,于是换了判断用的数据源,新增Room查询函数,直接从Room返回List<T>
实例,结果还是出现问题。
问了一下DeepSeek,排查总结如下:
- 确保DAO的delete方法是挂起函数
- 修改Repository中的删除方法为挂起函数
- 修改ViewModel中的删除方法为挂起函数
- 在Compose中调用时,确保使用协程作用域
按照DeepSeek给出的思路一步步排查,终于发现问题所在:
ViewModel中用于删除记录的删除函数viewModel.delete(item)
没有使用suspend
进行修饰来将该函数设置为挂起函数,而是作为普通函数使用viewModelScope.launch
将数据库异步删除操作给包裹了起来,导致协程不同步
也就是说,在scope.launch这个异步操作内,viewModel.delete(item)
对于viewModel.allItem.isNotEmpty()
也是一个异步操作而不是同步操作,导致还未完成删除就进入判断环节。
解决方法
将viewModel.delete(item)
函数添加suspend
修饰符并直接调用Room的异步删除操作,统一由最外围的rememberCoroutineScope(scope.launch)来控制协程,使得协程同步。
后记
这几天都在学Jetpack Compose,从传统的Android XML结构的app转向Android Jetpack Compose还是有点难度。以前更新控件直接用binding就可以,现在要用回调函数通过状态提升来更新控件,还有Flow与State之间的处理(头秃)
以前ViewModel除了用于延长UI属性的生命周期外都不带用的,现在Jetpack Compose不用ViewModel玩不了一点。不过设计理念还是蛮先进的,不知道是不是过于先进,网上中文资料少得可怜,幸好有DeepSeek来帮忙(躺)
Use this card to join MyBlog and participate in a pleasant discussion together .
Welcome to GoodBoyboy 's Blog,wish you a nice day .