You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Flow和协程在循环中收集数据并等待完成后更新UI

问题根源

你代码的核心问题是for循环内通过launch启动的子协程为异步执行,外层协程不会等待这些子协程全部执行完成,就会直接调用updateUI,此时列表还未完成所有详情数据的填充。

解决方案

根据你的getScheduleDetails的行为不同,可以选择对应的方案:

方案1:async + awaitAll(推荐,getScheduleDetails仅返回一次结果时使用)

不需要维护共享可变集合,天然避免线程安全问题,代码更简洁:

viewModelScope.launch {
    useCases.getScheduleList().collect { scheduleList ->
        // 为每个日程创建异步请求详情的任务
        val deferredList = scheduleList.map { schedule ->
            async {
                val detail = useCases.getScheduleDetails(schedule.code).first()
                newScheduleWithDetail(schedule, detail.body)
            }
        }
        // 等待所有异步请求完成,直接获取完整列表
        val schedulesWithDetails = deferredList.awaitAll()
        updateUI(schedulesWithDetails)
    }
}

方案2:Job + joinAll

如果需要保留launch的写法,可以存储所有子协程的Job对象,等待全部执行完成后再更新UI,注意要使用线程安全的集合存储结果:

viewModelScope.launch {
    useCases.getScheduleList().collect { scheduleList ->
        val jobList = mutableListOf<Job>()
        // 使用线程安全的列表避免并发添加数据出错
        val schedulesWithDetails = Collections.synchronizedList(arrayListOf<ScheduleWithDetails>())

        for (schedule in scheduleList) {
            val job = launch {
                val detail = useCases.getScheduleDetails(schedule.code).first()
                schedulesWithDetails.add(newScheduleWithDetail(schedule, detail.body))
            }
            jobList.add(job)
        }
        // 等待所有子协程执行完成
        jobList.joinAll()
        updateUI(schedulesWithDetails)
    }
}

方案3:Flow组合(getScheduleDetails会持续发射更新时使用)

如果详情数据后续会动态变更,需要响应式更新UI,可以使用combine操作符合并所有详情Flow,任意详情更新都会自动触发UI刷新:

viewModelScope.launch {
    useCases.getScheduleList()
        .flatMapLatest { scheduleList ->
            val detailFlows = scheduleList.map { schedule ->
                useCases.getScheduleDetails(schedule.code)
                    .map { detail -> newScheduleWithDetail(schedule, detail.body) }
            }
            combine(detailFlows) { it.toList() }
        }
        .collect { schedulesWithDetails ->
            updateUI(schedulesWithDetails)
        }
}

内容的提问来源于stack exchange,提问作者Rafael J Silva

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 19:15:03