知玩指南
白蓝主题五 · 清爽阅读
首页  > 驱动工具

Kotlin协程中用zip合并多个网络请求,省时又清爽

做 Android 开发时,经常要同时拉取用户信息、订单列表和未读消息数——三个接口,彼此独立,又得一起展示。以前用 Retrofit 配合 Callback 或 LiveData 拼接数据,写一堆回调嵌套或状态管理逻辑,一不小心就掉进“回调地狱”。现在 Kotlin 协程 + zip,三行代码搞定合并请求,干净利落。

zip 是什么?不是拉链,是并行聚合

zip 不是串行等一个完再跑下一个,而是让多个协程并发执行,等全部返回后,把结果按顺序打包成 Pair 或 Triple 一次性交给你。就像叫了三辆网约车,司机各自出发,你坐在家里等他们仨都到门口,再一起上车出发。

实际代码长这样

假设你有三个 suspend 函数:

suspend fun fetchUserInfo(): User { /* 网络调用 */ }
suspend fun fetchOrders(): List<Order> { /* 网络调用 */ }
suspend fun fetchUnreadCount(): Int { /* 网络调用 */ }

在 ViewModel 里启动协程,用 async 并发发起请求,再用 await()zip 合并:

viewModelScope.launch {
    try {
        val (user, orders, count) = async { fetchUserInfo() }
            .zip(async { fetchOrders() })
            .zip(async { fetchUnreadCount() })
            .await()
            .let { (pair, count) -> (pair.first, pair.second, count) }

        // 更新 UI:user、orders、count 全齐了
        _uiState.value = HomeUiState(user, orders, count)
    } catch (e: Exception) {
        _uiState.value = HomeUiState.error(e.message ?: "加载失败")
    }
}

注意:Kotlin 标准库的 zip 扩展默认只支持两个协程任务。如果要 zip 三个,就得套一层 zip().zip(),然后用 let 解构。更清爽的做法是引入 kotlinx-coroutines-core 1.7+ 的 awaitAll,但那是另一条路——这里聊的是原生 zip 思路,轻量、不加依赖。

别踩坑:zip 不等于 allOf

有人会混淆 zipawaitAll。前者严格按参数顺序配对返回值(第一个协程结果配第二个,再配第三个),后者返回的是 List<T>,你要自己下标取。如果你的三个请求返回类型不同(User、List<Order>、Int),zip 解构起来更直观;如果都是同类型,awaitAll 写法更扁平。

真实场景小提醒

某次上线前压测发现,首页加载慢了 800ms。查下来是三个接口被写成了串行 await:先等用户信息,再等订单,最后等消息数。改成 zip 后,总耗时直接降到最长那个接口的耗时(比如 300ms),体验立马顺滑。不是所有请求都适合 zip——比如第二个接口依赖第一个返回的 token,那就得老老实实 await;但凡能并行的,zip 就是驱动工具箱里那把趁手的梅花起子,拧得快、不打滑。