Kotlin中如何等待异步任务完成后返回正确结果?
解决方案
1. 将回调式异步函数转为挂起函数
你的getUserFromDatabase是回调风格的异步方法,首先需要把它包装成协程挂起函数,才能在协程中以同步方式调用:
// 包装原有回调方法为挂起函数 suspend fun getUserFromDatabase(id: String): User { return suspendCoroutine { continuation -> getUserFromDatabase(id) { user -> // 异步任务完成后恢复协程,返回结果 continuation.resume(user) } } }
2. 修改getUsersList为挂起函数,等待所有任务完成
使用async启动并行协程任务,通过awaitAll等待所有任务结束后返回完整列表:
suspend fun getUsersList(userIds: List<String>): List<User> { return coroutineScope { // 为每个userId启动异步任务 userIds.map { id -> async { getUserFromDatabase(id) } }.awaitAll() // 等待所有任务完成,返回结果集合 } }
这里的coroutineScope是结构化并发的核心,它会确保所有子协程执行完毕后再结束作用域,若任一子协程失败,所有子协程都会被取消,避免协程泄漏。
3. 构建Type1到User的映射Map(针对补充需求)
同样用协程并行处理,最终返回完整的映射关系:
suspend fun buildType1ToUserMap(type1List: List<Type1>): Map<Type1, User> { return coroutineScope { // 先为每个Type1创建对应的异步任务 val deferredMap = type1List.associateWith { type1 -> async { getUserFromDatabase(type1.userId) } } // 等待所有任务完成,转换为最终的Map deferredMap.mapValues { (_, deferred) -> deferred.await() } } }
4. 调用挂起函数的正确方式
挂起函数不能在普通函数中直接执行,需要在协程作用域内调用。比如在ViewModel中使用viewModelScope,在Activity/Fragment中使用lifecycleScope:
class MyViewModel : ViewModel() { fun loadData(type1List: List<Type1>) { viewModelScope.launch { // 等待获取完整用户列表 val userList = getUsersList(type1List.map { it.userId }) // 等待构建完成Type1与User的映射 val type1UserMap = buildType1ToUserMap(type1List) // 此处更新ViewModel状态,通知UI刷新 } } }
关键注意点
- 禁止在UI线程使用
runBlocking调用挂起函数,这会阻塞UI导致卡顿 async用于并行处理独立异步任务,比串行循环效率更高- 结构化并发(
coroutineScope)确保所有子任务被正确管理,杜绝协程泄漏
内容的提问来源于stack exchange,提问作者Exicode
相关产品推荐
相关产品推荐

