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
相关产品推荐
相关产品推荐

