You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin+Retrofit实现多线程并行执行多API请求优化加载性能

多API并行请求优化方案

现有代码存在的问题

你当前的实现本身用了Retrofit的enqueue异步请求,本身不会串行执行,但存在两个核心问题导致感知上加载慢:

  • 所有API请求共用同一个全局MutableLiveData实例,后返回的请求结果会覆盖之前的结果,你既无法区分返回结果对应哪个接口,也没法统一判断所有请求是否全部完成,只能收到一次结果就更新一次UI,重复渲染自然会卡
  • 没有做请求结果聚合,需要等所有接口返回才能完整渲染页面时,当前写法没有统一的完成回调,会拉长感知上的加载时间

方案1:基于ExecutorService实现并行请求

适合你要求的用executors、原生线程能力实现的需求:

Repository层修改

class Repository {
    // 配置和请求数量匹配的固定线程池,比如5次请求就设5个核心线程
    private val apiExecutor = Executors.newFixedThreadPool(5)

    // 把原有异步回调的请求改成同步执行,方便提交到线程池
    fun callApiOneSync(): Resource<Model> {
        return try {
            val response = AppMain.restClient?.services?.callApiOne()?.execute()
            if (response?.isSuccessful == true) {
                Resource.successResp(response)
            } else {
                Resource.errorresponse(response)
            }
        } catch (t: Throwable) {
            Resource.failure(t.message ?: "请求失败", null)
        }
    }

    // 按照上面的格式,补全callApiTwoSync、callApiThreeSync...所有你需要调用的接口

    // 批量并行请求方法,等待所有请求完成后统一返回结果
    fun batchCallAllApis(): List<Resource<*>> {
        val tasks = listOf(
            Callable { callApiOneSync() },
            Callable { callApiTwoSync() },
            Callable { callApiThreeSync() },
            // 把剩下的其他接口任务也加进来
        )
        // 提交所有任务,阻塞到所有任务执行完成后返回结果列表
        return apiExecutor.invokeAll(tasks).map { it.get() }
    }
}

ViewModel层修改

class MyViewModel: ViewModel() {
    val allApiResultLiveData = MutableLiveData<List<Resource<*>>>()

    fun callAllApis() {
        // 切到IO线程执行请求,避免阻塞主线程
        viewModelScope.launch(Dispatchers.IO) {
            val results = repository.batchCallAllApis()
            allApiResultLiveData.postValue(results)
        }
    }
}

Fragment层修改

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    viewModel.callAllApis()
    viewModel.allApiResultLiveData.observe(this.viewLifecycleOwner) { resultList ->
        // 所有请求已完成,在这里统一处理所有接口的返回结果,按顺序对应你提交的任务
        resultList.forEachIndexed { index, resource ->
            // 分别处理每个接口的成功/失败逻辑
        }
    }
}

方案2:更推荐的Kotlin协程实现

不需要自己维护线程池,Android官方原生支持,自动处理生命周期避免内存泄漏,代码更简洁:
首先先把你的Retrofit ApiService接口改成挂起函数:

interface ApiService {
    @GET("你的接口1路径")
    suspend fun callApiOne(): Response<Model>
    // 其他所有接口都加suspend关键字即可
}

Repository层修改

class Repository {
    // 每个接口改成挂起函数
    suspend fun callApiOne(): Resource<Model> {
        return try {
            val response = AppMain.restClient?.services?.callApiOne()
            if (response?.isSuccessful == true) {
                Resource.successResp(response)
            } else {
                Resource.errorresponse(response)
            }
        } catch (t: Throwable) {
            Resource.failure(t.message ?: "请求失败", null)
        }
    }

    // 补全其他接口的挂起实现

    // 并行请求方法
    suspend fun batchCallAllApis(): List<Resource<*>> = coroutineScope {
        val deferredTasks = listOf(
            async { callApiOne() },
            async { callApiTwo() },
            async { callApiThree() },
            // 加其他接口任务
        )
        // 等待所有请求完成返回结果
        deferredTasks.awaitAll()
    }
}

ViewModel和Fragment层的代码和方案1完全一致,不需要修改。

注意事项

  • 如果你有部分接口不需要等其他请求完成就能单独渲染,可以单独写对应的LiveData返回结果,不需要都放到批量请求里
  • 自定义的ExecutorService如果不在页面销毁时关闭,会有内存泄漏风险,用协程+viewModelScope的方案会在页面销毁时自动取消未完成的请求,更安全

内容的提问来源于stack exchange,提问作者hodokeg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:00:02