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

Kotlin中同一挂起函数重复调用时取消正在运行的前序任务

Kotlin实现点击防抖、自动取消前序执行任务的方案

Kotlin协程原生支持该能力,不需要额外依赖第三方库,核心是利用协程Job的可取消特性,就能实现「新调用触发时自动终止还在delay等待阶段的前序任务,仅保留最后一次连续点击的日志输出」的需求。

核心实现逻辑

  • 维护一个协程Job变量,用来持有当前正在执行的计数器递增任务引用
  • 每次点击触发新任务前,先调用前序Job的cancel()方法,直接中断未执行完的前序任务
  • 协程的delay()是标准的可取消挂起函数,任务被取消时会立刻终止等待流程,不会继续执行后续的日志打印逻辑

适配现有代码的实现示例

示例代码用到了mutableStateOf,适配Compose/Android开发场景,建议绑定生命周期感知的协程作用域避免内存泄漏:

// 持有正在运行的计数器任务引用
private var addCounterJob: Job? = null
// 请替换为当前场景对应的生命周期绑定作用域:
// Compose中用rememberCoroutineScope(),ViewModel中用viewModelScope,页面中用lifecycleScope
private val scope = rememberCoroutineScope() 

val counter = mutableStateOf(0)

// 点击事件直接绑定这个方法
fun onCounterClick() {
    // 新点击到来,先取消上一个还在等待的任务
    addCounterJob?.cancel()
    // 启动新的协程任务
    addCounterJob = scope.launch {
        addCounter()
    }
}

suspend fun addCounter(){
    delay(2000)
    // === 逻辑位置调整说明 ===
    // 1. 如果需要只有最后一次有效点击才累加计数:把counter.value++放在delay后面,和日志同位置
    // 2. 如果需要每次点击都立刻累加计数,只是不打印中间过程的日志:把counter.value++挪到onCounterClick里、cancel()之后的位置
    counter.value++
    Log.e("click cat","click $counter")
}

可选场景调整

如果你需要每次点击都立刻更新计数,只是过滤掉2秒内连续点击的重复日志,直接把计数累加逻辑挪到点击入口即可:

fun onCounterClick() {
    addCounterJob?.cancel()
    counter.value++ // 每次点击立刻加1,不受协程取消影响
    addCounterJob = scope.launch {
        delay(2000)
        Log.e("click cat","click $counter")
    }
}

注意:不要用GlobalScope启动这类和UI绑定的协程,否则会脱离生命周期管控造成内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:54:27