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

能否直接在onClick回调监听器中实现debounce防抖功能?

自定义MapView缩放监听器内置防抖实现方案

可以直接在自定义监听器内部通过Android原生Handler实现防抖逻辑,完全不需要依赖协程实验API,同时封装度更高,调用更简洁。

改造后的完整代码

import android.os.Handler
import android.os.Looper
import android.view.View
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import java.lang.ref.WeakReference

class ZoomMapListener(
    mapView: MapView,
    private val zoom: Zoom,
    // 支持自定义防抖间隔,默认500ms
    private val debounceDelay: Long = 500L,
    // 可选传入生命周期自动解绑,避免内存泄漏
    lifecycle: Lifecycle? = null
) : View.OnClickListener {

    private val localMapView = WeakReference(mapView)
    private var clickCount = 0
    private val mainHandler = Handler(Looper.getMainLooper())
    private val moveCameraTask = Runnable { moveCamera() }

    init {
        // 传入生命周期的话,在页面销毁时自动清理待执行任务
        lifecycle?.addObserver(object : DefaultLifecycleObserver {
            override fun onDestroy(owner: LifecycleOwner) {
                super.onDestroy(owner)
                mainHandler.removeCallbacks(moveCameraTask)
            }
        })
    }

    override fun onClick(view: View?) {
        clickCount++
        // 每次点击都重置防抖计时器
        mainHandler.removeCallbacks(moveCameraTask)
        mainHandler.postDelayed(moveCameraTask, debounceDelay)
    }

    private fun moveCamera() {
        val mapView = localMapView.get() ?: return

        val currentCamera = mapView.map.cameraPosition
        val targetZoom = if (zoom == Zoom.IN) {
            currentCamera.zoom + 1.0f * clickCount
        } else {
            currentCamera.zoom - 1.0f * clickCount
        }

        val newCamera = CameraPosition(
            currentCamera.target,
            targetZoom,
            currentCamera.azimuth,
            currentCamera.tilt
        )

        clickCount = 0
        mapView.map.move(newCamera, Animation(Animation.Type.SMOOTH, 0.5f), null)
    }

    // 提供手动取消待执行任务的入口
    fun cancelPendingTask() {
        mainHandler.removeCallbacks(moveCameraTask)
    }
}

enum class Zoom {
    IN, OUT
}

调用方式

不需要额外编写View扩展函数,也不需要手动传入协程作用域,符合原生点击事件的使用习惯:

// 基础调用
zoomInMapButton.setOnClickListener(ZoomMapListener(mapView, Zoom.IN))
zoomOutMapButton.setOnClickListener(ZoomMapListener(mapView, Zoom.OUT))

// 带自定义参数的调用(推荐)
zoomInMapButton.setOnClickListener(ZoomMapListener(
    mapView = mapView,
    zoom = Zoom.IN,
    debounceDelay = 600L,
    lifecycle = viewLifecycleOwner.lifecycle
))

优化说明

  • 完全移除了协程实验API依赖,仅用Android原生组件实现防抖逻辑,稳定性更高
  • 所有缩放相关逻辑完全内聚在监听器类内部,职责更清晰,不需要额外的工具类/扩展函数
  • 支持自定义防抖间隔、可选生命周期绑定,灵活性和安全性都优于原有实现
  • 调用方式更简洁,和原生Android View的点击事件使用习惯完全对齐

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 03:54:03