题目
在ViewModel中正确使用Kotlin协程处理异步任务
信息
- 类型:问答
- 难度:⭐⭐
考点
Kotlin协程, Android生命周期感知, ViewModel最佳实践
快速回答
在ViewModel中使用协程处理异步任务时:
- 使用
viewModelScope自动绑定ViewModel生命周期 - 在
init或事件响应中启动协程 - 使用
launch或async进行异步操作 - 通过
try/catch或CoroutineExceptionHandler处理异常 - 避免在ViewModel中直接暴露
suspend函数给UI层
原理说明
在Android开发中,ViewModel负责管理UI相关数据,而协程提供异步操作能力。关键点在于:
- 生命周期感知:
viewModelScope是ViewModel的Kotlin扩展,当ViewModel被清除(onCleared)时自动取消所有子协程 - 结构化并发:协程通过作用域(CoroutineScope)管理任务层级,避免内存泄漏
- 线程切换:协程通过Dispatchers指定执行线程(如IO/Default/Main)
代码示例
class MyViewModel : ViewModel() {
private val _data = MutableLiveData<String>()
val data: LiveData<String> = _data
init {
loadData()
}
private fun loadData() {
// 使用viewModelScope启动协程
viewModelScope.launch(Dispatchers.IO + exceptionHandler) {
val result = repository.fetchData() // 挂起函数
withContext(Dispatchers.Main) {
_data.value = result
}
}
}
private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
// 处理异常
}
}最佳实践
- 作用域选择:始终使用
viewModelScope而非自行创建作用域 - 线程调度:耗时操作使用
Dispatchers.IO,UI更新切回Dispatchers.Main - 异常处理:为关键协程添加异常处理器,避免崩溃
- 状态封装:通过LiveData/StateFlow将结果暴露给UI层
常见错误
- 错误1:在ViewModel中使用
GlobalScope导致生命周期无法绑定 - 错误2:在UI层(Activity/Fragment)直接调用
launch处理业务逻辑 - 错误3:忘记处理协程异常导致崩溃未被捕获
- 错误4:在
onCleared()中手动取消协程(viewModelScope已自动处理)
扩展知识
- StateFlow替代LiveData:在协程环境中更推荐使用StateFlow进行状态管理
- 协程测试:使用
TestDispatcher和runTest进行单元测试 - 复杂任务处理:使用
async/await进行并行操作,supervisorScope处理独立子任务 - 冷流转换:通过
flow { ... }.stateIn(viewModelScope)将冷流转换为热流