MutableStateFlow控制加载状态不更新UI的问题解决
解决加载Spinner不显示的问题
你的判断完全正确——ViewModel的change()函数中,coordinator.change()只是启动了一个后台协程就立即返回,导致_isChanging.value = false紧接着执行,UI还没来得及响应true的状态,Spinner自然不会显示。以下是几种可行的解决方案:
方案一:改造Coordinator为挂起函数(推荐)
这是最符合Kotlin协程最佳实践的方式,让耗时操作成为挂起函数,由ViewModel的viewModelScope管理协程生命周期:
修改Coordinator代码
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) // 改为挂起函数,直接执行耗时逻辑 suspend fun change() { delay(5000) // 耗时操作 }
修改ViewModel代码
@HiltViewModel class MyViewModel @Inject constructor( val coordinator: MyCoordinator ) : ViewModel() { private val _isChanging = MutableStateFlow(false) val isChanging = _isChanging.asStateFlow() fun change() { // 使用viewModelScope启动协程,自动绑定ViewModel生命周期 viewModelScope.launch { _isChanging.value = true coordinator.change() // 等待耗时操作完成 _isChanging.value = false } } }
方案二:让Coordinator返回Job,ViewModel等待完成
如果不想修改Coordinator的函数类型,可以让它返回启动的协程Job,ViewModel中等待Job执行完毕:
修改Coordinator代码
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) fun change(): Job { return applicationScope.launch { delay(5000) } }
修改ViewModel代码
fun change() { viewModelScope.launch { _isChanging.value = true coordinator.change().join() // 等待后台协程完成 _isChanging.value = false } }
方案三:通过回调更新状态
也就是你提到的传入Lambda的方式,注意要在主线程更新状态(因为Coordinator的协程在IO线程):
修改Coordinator代码
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) fun change(onStart: () -> Unit, onComplete: () -> Unit) { applicationScope.launch { // 切换到主线程更新状态 withContext(Dispatchers.Main) { onStart() } delay(5000) withContext(Dispatchers.Main) { onComplete() } } }
修改ViewModel代码
fun change() { coordinator.change( onStart = { _isChanging.value = true }, onComplete = { _isChanging.value = false } ) }
内容的提问来源于stack exchange,提问作者toshiomagic
相关产品推荐
相关产品推荐

