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

如何实现ViewModel多并发请求的响应队列匹配机制?

解决ViewModel请求响应错位的队列实现方案

问题背景

现有代码逻辑:

  • 携带request()方法的对象,通过调用监听器的onRequest(::setList)发起请求,setList会根据listType分发数据
  • 重写后的onRequest方法会检查ViewModel的listItemsResult(MutableLiveData<List<ListItems>>),若为空则调用loadListItems从API拉取数据,并通过observe监听数据变化后回调setList
  • ViewModel的loadListItems方法通过viewModelScope发起API请求,获取数据后用postValue更新listItemsResult

当前问题:当多个带request()的对象同时发起请求时,由于不同API的返回速度存在差异,缺乏队列机制会导致响应与请求错位(例如A请求的响应被错误匹配给B请求)。

解决方案

方案1:为请求绑定唯一标识,精准匹配响应

核心思路:给每个请求分配唯一ID,ViewModel发起API请求时携带该ID,返回数据时将ID与结果一起封装,确保只有匹配ID的请求才处理对应响应。

步骤:

  1. 修改onRequest方法,生成唯一请求ID(如UUID、自增序列),并将ID与setList回调绑定存储
  2. ViewModel的loadListItems方法接收请求ID,发起API请求时携带ID,返回数据封装为Pair<String, List<ListItems>>(ID+结果)
  3. 将listItemsResult的类型改为MutableLiveData<Pair<String, List<ListItems>>>
  4. 监听listItemsResult时,仅处理与当前请求ID匹配的结果,处理完成后清理对应映射关系

代码示例:

// 请求发起方
private val requestCallbackMap = mutableMapOf<String, (List<ListItems>) -> Unit>()

fun onRequest(callback: (List<ListItems>) -> Unit) {
    val requestId = UUID.randomUUID().toString()
    requestCallbackMap[requestId] = callback
    viewModel.loadListItems(requestId)
}

// ViewModel侧
val listItemsResult = MutableLiveData<Pair<String, List<ListItems>>>()

fun loadListItems(requestId: String) {
    viewModelScope.launch {
        val data = apiService.getListItems()
        listItemsResult.postValue(requestId to data)
    }
}

// 结果监听方
viewModel.listItemsResult.observe(this) { (responseId, data) ->
    requestCallbackMap.remove(responseId)?.invoke(data)
}

方案2:串行请求队列,逐个处理请求

核心思路:维护一个请求队列,ViewModel每次仅处理队列中的一个请求,上一个请求完成后再处理下一个,从根源避免并发冲突。

步骤:

  1. 在ViewModel中用Channel实现请求队列(支持无限容量)
  2. 启动协程循环从队列中取出请求,串行执行API调用并回调结果
  3. 发起请求时,将回调逻辑传入队列等待处理

代码示例:

// ViewModel侧
private val requestQueue = Channel<(List<ListItems>) -> Unit>(Channel.UNLIMITED)

init {
    viewModelScope.launch {
        // 循环处理队列中的请求,保证串行执行
        for (callback in requestQueue) {
            val data = apiService.getListItems()
            callback(data)
        }
    }
}

fun loadListItems(callback: (List<ListItems>) -> Unit) {
    viewModelScope.launch {
        requestQueue.send(callback)
    }
}

// 请求发起方
fun onRequest(callback: (List<ListItems>) -> Unit) {
    viewModel.loadListItems(callback)
}

方案3:按请求类型维护独立LiveData

核心思路:如果请求是按listType区分的,为每个listType单独创建对应的LiveData,不同类型的请求更新各自的LiveData,避免互相干扰。

步骤:

  1. 在ViewModel中用HashMap存储不同listType对应的LiveData实例
  2. 请求时根据listType获取或创建对应的LiveData
  3. 监听对应listType的LiveData变化,仅回调给当前请求

代码示例:

// ViewModel侧
private val liveDataMap = mutableMapOf<String, MutableLiveData<List<ListItems>>>()

fun getListLiveData(listType: String): MutableLiveData<List<ListItems>> {
    return liveDataMap.getOrPut(listType) { MutableLiveData() }
}

fun loadListItems(listType: String) {
    viewModelScope.launch {
        val data = apiService.getListItemsByType(listType)
        getListLiveData(listType).postValue(data)
    }
}

// 请求发起方
fun onRequest(listType: String, callback: (List<ListItems>) -> Unit) {
    val liveData = viewModel.getListLiveData(listType)
    if (liveData.value == null) {
        viewModel.loadListItems(listType)
    }
    liveData.observe(this) { data ->
        callback(data)
        // 可选:若无需持续监听,处理完成后移除观察者
        liveData.removeObserver(this)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:57:37