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

Kotlin Flow的onEach操作符内过滤集合不生效问题及解决方案

问题场景

在特定业务用例中,调用Repository层接口获取Flow类型的数据,类型为:

Flow<Resource<List<Location>>>

相关定义说明

  • Resource是封装类,定义如下:
sealed class Resource<T>(val data: T? = null, val message: String? = null) {
    class Loading<T>(data: T? = null): Resource<T>(data)
    class Success<T>(data: T?): Resource<T>(data)
    class Error<T>(message: String, data: T? = null): Resource<T>(data, message)
}
  • Location为自定义数据模型类,每个实例都带有type属性。

需求为:当用户切换到对应类型的板块时,触发用例方法发起API请求,对返回的列表做过滤,仅保留符合当前类型的条目。

问题表现

最初实现的过滤逻辑不生效,代码如下:

return repository.getLocations()
        .onEach { result ->
            if (result.data != null) {
                when (locationType) {
                    is LocationType.All -> result.data
                    is LocationType.Hotel -> result.data.filter { it.type == "Hotel" }
                    is LocationType.Explore -> result.data.filter { it.type == "Explore" }
                    is LocationType.Active -> result.data.filter { it.type == "Active" }
                    is LocationType.Restaurant -> result.data.filter { it.type == "Restaurant" }
                }   
            }
        }

即便添加了onEach逻辑,最终返回的列表也没有变化。

补充说明:Repository接口的返回类型固定为Flow<Resource<List<Location>>>。

原因说明

onEach属于Flow的副作用操作符,仅会对上游发射的每个数据执行指定的逻辑,不会修改上游发射的原始值,也不会向下游发射新的值。上述代码中在onEach内执行filter生成了新的过滤后列表,但没有做任何返回或发射操作,下游收到的还是原始的Resource对象,因此过滤不生效。

解决方案

可在用例中构建新的Flow,收集上游返回的数据后做过滤处理,再向下游发射处理后的Resource对象即可,实现代码如下:

operator fun invoke(
    locationType: LocationType
) = flow {
     repository.getLocations().collect { result ->
        result.data?.let { originData ->
            // 先按类型过滤列表
            val filteredList = when (locationType) {
                is LocationType.All -> originData
                is LocationType.Hotel -> originData.filter { it.type == "Hotel" }
                is LocationType.Explore -> originData.filter { it.type == "Explore" }
                is LocationType.Active -> originData.filter { it.type == "Active" }
                is LocationType.Restaurant -> originData.filter { it.type == "Restaurant" }
            }
            // 保留原有Resource状态,替换为过滤后的列表向下游发射
            when (result) {
                is Resource.Success -> emit(Resource.Success(data = filteredList))
                is Resource.Loading -> emit(Resource.Loading(data = filteredList))
                is Resource.Error -> emit(Resource.Error(data = filteredList, message = result.message ?: ""))
            }
        }
     }
}

内容的提问来源于stack exchange,提问作者mikolaj-jalocha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 21:15:03