Kotlin新技巧: combine 函数组合多个 Flow

社区移动开发Android
高级 Kotlin 技巧: 在 Android 开发中释放combine的强大力量! 🧠💪

picture.image

举NHL示例充分利用combine以合并 3 个流用来增强简明性和可读性

简介

在 Android 开发领域, Kotlin 已成为一种强大而富有表现力的语言. 其突出特点之一是能够使用协程和Flow来处理异步操作. 在众多可用工具中, combine函数为同时处理多个流提供了一种简洁高效的方法.

使用combine是初级, 中级还是专家级方法?

虽然与基本的协程概念相比, combine是一个相对高级的功能, 但它并不是专家的专属. 只要扎实地理解了协程和Flow, 中级开发人员就能有效地利用combine来增强他们的 Android 应用程序.

初始代码与重构代码的对比

上图是 NHL 球队比赛的屏幕截图; 代码从三个不同的服务中并行获取数据: 今天的比赛, 选定日期的比赛和球队排名.

分解初始方法

代码不是以线性方式等待每个服务调用依次完成, 而是利用asyncawait模式为每个请求启动并发 协程, 从而提高性能.

  • 每个Flow都有单独的 async 块.
  • 手动处理延迟结果和UI状态.
  • 缺乏明确的try-catch块, 无法从容应对失败.
  • 使用firstOrNull, 只能得到第一个结果. 如果有新数据(玩家信息的实时更新, 时间变化等)怎么办?
    fun loadScreenData(isRefreshedGames; Boolean, date: String) {
        viewModelScope.launch {
            val todayOnlyGamesDeferred = async {
                repository.getGames(localDate.format(date)).firstOrNull()?.games.orEmpty()
            }
            val anyDayGamesDeferred = async {
                repository.getGames(_selectedDate.value).firstOrNull()?.games.orEmpty()
            }
            val teamsDeferred = async {
                repository.getStandingsNow().firstOrNull().orEmpty()
            }
            _uiState.emit(
                GamesUiState.Success(
                    games = if (isRefreshedGames) anyDayGamesDeferred.await() else todayOnlyGamesDeferred.await(),
                    teams = teamsDeferred.await()
                )
            )
        }
    }
使用combine 的重构方法
  • 使用单个combine调用来组合Flow, 该调用依赖于非阻塞 D.I. ioDispatcher.
  • 使用 lambda 函数将合并的值转换为所需的UI状态.
  • 使用 collect 直接发送UI状态.
  • try-catch 块包围, 用于处理调用失败或任何类型的异常. ❌⛔❗✅
suspend fun loadScreenData(isRefreshedGames; Boolean, date: String) = withContext(ioDispatcher) {
    try {
        viewModelScope.launch(coroutineExceptionHandler) {
            val todayOnlyGamesFlow = repository.getGames(localDate.format(date)).map { it.games }
            val anyDayGamesFlow = repository.getGames(_selectedDate.value).map { it.games }
            val teamsFlow = repository.getStandingsNow().map { it }

            combine(todayOnlyGamesFlow, anyDayGamesFlow, teamsFlow) { todayGames, anyDayGames, teams ->
                GamesUiState.Success(
                    games = if (withRefreshedGames) anyDayGames else todayGames,
                    teams = teams 
                )
            }.collect { uiState ->
                _uiState.emit(uiState)
            }
        }
    } catch (e: Throwable) {
        _uiState.emit(GamesUiState.Error(e))
    }
}
摘要: 为什么在 Android 中使用 combine?
  1. 简化代码: combine 提供了一种简洁, 可读的方式来处理多个Flow, 使你的代码更易于理解和维护.
  2. 高效数据处理: 通过组合Flow, 你可以同时处理多个来源的数据, 从而提高性能.
  3. 主动更新: combine允许对UI状态进行主动更新, 确保其始终反映最新数据.
  4. 增强灵活性: combine可灵活处理组合值, 允许你在输出最终结果之前执行额外的变换或计算.

今天要分享的内容就这么些啦!

一家之言, 欢迎斧正!

Happy Coding! Stay GOLDEN!

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论