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

如何高效合并并缓存两个Kotlin Flow以避免重复网络请求?

问题

我有两个无法修改的库函数:

fun list(): Flow<List<ID>>

和

fun propertiesById(id: ID): Flow<List<Prop>>

需求是将二者合并,获取ID及其所有属性的完整信息(属性可能会更新)。

目前的实现如下:

val result = list().flatMapLatest { ids ->
    val propFlow = ids.map { id ->
        propertiesById(id).map { props ->
            MyClass(id, props)
        }
    }
    combine(propFlow) { it.toList() }
}

该实现能正常返回Flow<List<MyClass>>,但存在效率问题:每当ID列表新增或移除元素时,对应的propertiesById Flow会被取消并重新创建,而这个Flow涉及网络请求,反复重建会大幅降低性能。

请问是否有办法缓存propertiesById的Flow,使得ID列表更新时,能复用已有的Flow,避免反复取消和创建?

解决方案

核心思路是缓存每个ID对应的propertiesById Flow实例,当ID列表更新时,只对新增的ID创建新Flow,对保留的ID复用已有Flow,对移除的ID清理对应的Flow。

可以通过一个映射表维护缓存,结合transformLatest操作符处理ID列表的更新:

// 缓存每个ID对应的Flow,确保同一个ID只创建一次Flow实例
private val idFlowCache = mutableMapOf<ID, Flow<MyClass>>()

val result = list().transformLatest { currentIds ->
    // 1. 清理已移除的ID对应的缓存
    val removedIds = idFlowCache.keys - currentIds
    removedIds.forEach { id ->
        idFlowCache.remove(id)
    }

    // 2. 为新增的ID创建Flow并加入缓存
    val addedIds = currentIds - idFlowCache.keys
    addedIds.forEach { id ->
        val flow = propertiesById(id)
            .map { props -> MyClass(id, props) }
            .onCompletion {
                // 当Flow意外完成时自动移除缓存(可选,根据业务场景调整)
                idFlowCache.remove(id)
            }
        idFlowCache[id] = flow
    }

    // 3. 合并当前所有有效Flow并发射结果
    val activeFlows = currentIds.mapNotNull { idFlowCache[it] }
    combine(activeFlows) { it.toList() }
        .collect { emit(it) }
}

关键细节说明:

  • 缓存复用:同一个ID只会触发一次propertiesById调用,后续只要ID还在列表中,就直接复用缓存的Flow,彻底避免重复网络请求。
  • 资源回收:当ID从列表中移除时,从缓存中删除对应的Flow,Kotlin Flow会在没有收集者时自动取消,释放网络连接等资源。
  • 线程安全优化:如果是多线程场景,可将mutableMapOf替换为ConcurrentHashMap,避免并发操作冲突:
private val idFlowCache = ConcurrentHashMap<ID, Flow<MyClass>>()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 15:15:59