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

寻找适配异步生成ReportCard的Kotlin Flow运算符

两种发射方式对应的Flow实现方案

场景1:每次获取到成绩就发射更新后的列表

这种场景适合滚动列表即时刷新,每拿到一个学生的成绩就推送一次完整的更新后列表。

核心逻辑:

  1. 先发射初始空成绩列表(从getPeople()生成,grade用空字符占位)
  2. 对每个Person并行发起getStudent()请求,捕获异常并忽略失败的请求
  3. 每次拿到有效成绩时,更新对应位置的ReportCard并发射完整列表

实现代码(结合Flow运算符):

fun getReportCardsFlow(): Flow<List<ReportCard>> = flow {
    // 1. 发射初始列表
    val initialCards = getPeople().map { ReportCard(it.name, ' ') }
    emit(initialCards)

    // 2. 为每个Person创建异步获取成绩的Flow
    val updateFlows = getPeople().map { person ->
        flow {
            runCatching { getStudent(person.ssn) }
                .onSuccess { student ->
                    // 更新对应ReportCard的成绩
                    val updatedCards = initialCards.map {
                        if (it.name == person.name) it.copy(grade = student.grade) else it
                    }
                    emit(updatedCards)
                }
                // 忽略错误,不触发更新
        }.flowOn(Dispatchers.IO)
    }

    // 3. 合并所有更新Flow,有结果就发射
    merge(*updateFlows.toTypedArray()).collect { emit(it) }
}

关键Flow运算符:

  • flow:自定义Flow构建器,控制初始列表和后续更新的发射时机
  • flowOn:指定异步请求的调度线程(IO线程)
  • merge:合并多个更新Flow,任何一个Flow产生结果时都会触发收集

场景2:所有成绩获取完成后再发射最终列表

这种场景仅发射两次结果:初始空列表、所有请求完成后的最终列表,适合不需要实时刷新的场景。

核心逻辑:

  1. 先发射初始空成绩列表
  2. 并行发起所有getStudent()请求,收集所有成功获取的成绩
  3. 批量更新列表后发射最终结果

实现代码(结合Flow运算符):

fun getFinalReportCardsFlow(): Flow<List<ReportCard>> = flow {
    val initialCards = getPeople().map { ReportCard(it.name, ' ') }
    // 1. 发射初始列表
    emit(initialCards)

    // 2. 并行处理所有请求,收集有效成绩映射
    val gradeMap = coroutineScope {
        getPeople().map { person ->
            async(Dispatchers.IO) {
                runCatching { getStudent(person.ssn) }
                    .getOrNull()?.let { person.ssn to it.grade }
            }
        }.awaitAll().filterNotNull().toMap()
    }

    // 3. 生成最终列表并发射
    val finalCards = initialCards.map { card ->
        val person = getPeople().first { it.name == card.name }
        card.copy(grade = gradeMap[person.ssn] ?: ' ')
    }
    emit(finalCards)
}

关键Flow相关实现:

  • flow:自定义Flow构建器,控制两次结果的发射时机
  • 结合协程async/awaitAll实现并行请求(若getStudent返回Flow,可替换为flatMapMerge批量处理)

补充提示

  • 错误处理统一用runCatching或Flow的catch运算符,确保单个请求失败不中断整体流程
  • 若getStudent本身是返回Flow的方法,可直接替换为getStudent(person.ssn).catch {}.map { ... }处理异步和错误

内容的提问来源于stack exchange,提问作者HukeLau_DABA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:07:44