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

简介

在 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可灵活处理组合值, 允许你在输出最终结果之前执行额外的变换或计算.
阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.dandroid.cn/archives/22860,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?