如何实现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的请求才处理对应响应。
步骤:
- 修改
onRequest方法,生成唯一请求ID(如UUID、自增序列),并将ID与setList回调绑定存储 - ViewModel的
loadListItems方法接收请求ID,发起API请求时携带ID,返回数据封装为Pair<String, List<ListItems>>(ID+结果) - 将
listItemsResult的类型改为MutableLiveData<Pair<String, List<ListItems>>> - 监听
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每次仅处理队列中的一个请求,上一个请求完成后再处理下一个,从根源避免并发冲突。
步骤:
- 在ViewModel中用
Channel实现请求队列(支持无限容量) - 启动协程循环从队列中取出请求,串行执行API调用并回调结果
- 发起请求时,将回调逻辑传入队列等待处理
代码示例:
// 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,避免互相干扰。
步骤:
- 在ViewModel中用
HashMap存储不同listType对应的LiveData实例 - 请求时根据
listType获取或创建对应的LiveData - 监听对应
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
相关产品推荐
相关产品推荐

