用户发起新查询请求时如何取消前序未完成的coroutine协程?
实现方案
核心逻辑是在ViewModel中持有当前查询协程的引用,每次发起新查询前先取消上一次的未完成协程:
步骤1:在ViewModel中新增协程引用变量
声明私有变量存储当前正在执行的天气查询协程的Job实例:
// 放在ViewModel类内部的成员变量位置 private var currentSearchJob: Job? = null
步骤2:修改getWeatherByCityName方法
每次触发查询时,先取消上一次的协程,再启动新协程并保存其Job引用。同时原代码中viewModelScope.launch嵌套launchIn(viewModelScope)属于冗余写法,可以同步优化:
fun getWeatherByCityName( cityName: String ) { // 先取消上一次未完成的查询协程,已完成的协程调用cancel不会抛出异常 currentSearchJob?.cancel() // 启动新协程并保存Job实例 currentSearchJob = weatherRepository.getWeatherByCityName(cityName, localeUnit, localeLang) .onEach { dataState -> when (dataState) { is ApiResult.Success -> { prefRepository.setUserInput(cityName) cityId = dataState.data.cityId _screenState.value = dataState } else -> _screenState.value = dataState } } .launchIn(viewModelScope) }
注意事项
- 只要仓库层的网络请求基于Kotlin协程实现(比如使用Retrofit官方协程适配器),协程取消时会自动终止未完成的网络请求,不会产生无效资源消耗
- 原有UI层的
handler.removeCallbacksAndMessages(null)已经实现了输入防抖时延迟任务的取消,搭配协程取消即可完整覆盖所有无效请求的场景
内容的提问来源于stack exchange,提问作者Dante313
相关产品推荐
相关产品推荐

