返回

Kotlin Flows 组合指南:应对筛选和分组更改的最佳实践

Android

组合 Kotlin Flows 成为一个 Flow 的最佳实践

简介

在 Android 应用程序开发中,我们经常需要在应用程序的不同组件之间传递数据。Flows 作为 Kotlin 协程中强大的工具,提供了处理异步流数据的一种优雅方式。有时,我们可能需要组合多个 Flows 以创建另一个 Flow,而这正是本文要探讨的内容。

需求和挑战

考虑以下场景:在用户界面中,用户可以为订单列表设置过滤和分组条件。这些条件表示为可变 Flows。每次日期筛选器发生更改时,都需要触发存储库函数以返回一个 Flow,该 Flow 应在更新的分组条件或存储库发送更新时,使用 UI 或 ViewModel 中的分组条件处理订单列表。

flatMapLatest:一个有缺陷的解决方案

最初,我们可能尝试使用 flatMapLatest 运算符来解决此问题,如下所示:

val orderTotalsFlow = dateEnd.flatMapLatest { de ->
    orderItemsRepository.findByDates(dateStart.value, de)
        .map {
            // 在此实现分组,使用 grouping Flow
        }
}

然而,这种方法在用户更新 grouping Flow 时会失效,因为 flatMapLatest 运算符会立即取消上一个 Flow 的订阅,从而无法接收到分组条件的更新。

combine:一个无效的解决方案

combine 运算符似乎是一个合理的替代方案,但它会返回一个 Flow<Flow<List>>>,这不符合我们的需求。

解决方案:使用 pairwise

正确的解决方案是使用 pairwise 运算符。pairwise 会将 Flow 中的每个元素与前一个元素配对,从而允许我们在每个元素变化时执行操作。以下是如何使用 pairwise 编写此代码:

val orderTotalsFlow = dateEnd.pairwise { prevDate, curDate ->
    orderItemsRepository.findByDates(dateStart.value, curDate)
        .map {
            // 在此实现分组,使用 grouping Flow
        }
}

在这里,pairwise 会在每次 dateEnd 发生更改时触发 findByDates 函数,并使用新旧日期值配对调用它。

优点

使用 pairwise 的优点如下:

  • 响应每个筛选器和分组条件更改。
  • 简洁优雅的解决方案。
  • 避免了 flatMapLatest 的取消问题和 combine 的返回类型不匹配问题。

最佳实践

  • 尽量避免使用 flatMapLatest,因为它会导致意外的取消订阅。
  • 优先使用 pairwise 来响应 Flow 中元素的成对更改。
  • 当需要组合多个 Flows 时,请考虑 combinezip 等其他运算符。

常见问题解答

  1. 为什么使用 pairwise 而不是 flatMapLatest

    • pairwise 不会取消上一个 Flow 的订阅,而 flatMapLatest 会。
  2. pairwisecombine 之间的区别是什么?

    • pairwise 配对 Flow 中的元素,而 combine 将多个 Flows 的元素组合在一起。
  3. 什么时候应该使用 zip

    • 当您需要将两个或多个 Flows 中的元素同时组合在一起时,应该使用 zip
  4. 如何在 ViewModel 中实现此解决方案?

    • 在 ViewModel 中创建 pairwise 流,并在其中调用存储库函数。
  5. 如何处理分组逻辑?

    • 可以使用 map 运算符在 pairwise 流中实现分组逻辑。