Android 防抖和节流
概述
- 防抖(Debounce):
- 防抖是指在事件被触发后,等待一段时间,如果在这段时间内没有再触发事件,才执行处理函数。如果在这段时间内又触发了事件,就重新开始计时。
- 场景:适用于频繁触发的事件,如:输入框搜索。
- 节流(Throttle):
- 节流是指在一定时间间隔内,无论事件触发多少次,只执行一次处理函数。
- 场景:适用于限制频率的操作,如:提交按钮。
工具类
object DebounceThrottleUtils {
private val handler = Handler(Looper.getMainLooper())
private val debounceMap = ConcurrentHashMap<String, Runnable>()
private val throttleMap = ConcurrentHashMap<String, Long>()
fun debounce(key: String, delayMillis: Long, block: () -> Unit) {
debounceMap[key]?.let {
handler.removeCallbacks(it)
debounceMap.remove(key)
}
val runnable = Runnable {
block()
}
debounceMap.put(key, runnable)
handler.postDelayed(runnable, delayMillis)
}
fun throttle(key: String, intervalMillis: Long, block: () -> Unit) {
val now = System.currentTimeMillis()
val lastTime = throttleMap[key] ?: 0
if (now - lastTime >= intervalMillis) {
throttleMap[key] = now
block()
}
}
fun clear(key: String) {
debounceMap[key]?.let {
handler.removeCallbacks(it)
debounceMap.remove(key)
}
throttleMap.remove(key)
}
fun clearAll() {
handler.removeCallbacksAndMessages(null)
debounceMap.clear()
throttleMap.clear()
}
}
fun View.getKey(): String {
return "click_${this.id}"
}
fun EditText.getKey(): String {
return "text_change_${this.id}"
}
fun View.clickDebounce(debounceTime: Long = 500L, action: () -> Unit) {
val key = getKey()
setOnClickListener {
DebounceThrottleUtils.debounce(key, debounceTime, action)
}
}
fun View.clickThrottle(throttleTime: Long = 300L, action: () -> Unit) {
val key = getKey()
setOnClickListener {
DebounceThrottleUtils.throttle(key, throttleTime, action)
}
}
fun EditText.textChangeDebounce(debounceTime: Long = 300L, action: (Editable?) -> Unit) {
doAfterTextChanged { editable ->
val key = getKey()
DebounceThrottleUtils.debounce(key, debounceTime, {
action(editable)
})
}
}
使用
etSearch.textChangeDebounce(debounceTime = 1000L) {
Log.e("TAG", "textChange:${it.toString()}")
}
btnSubmit.clickDebounce(debounceTime = 1000L) {
Log.e("TAG", "click-debounce-${System.currentTimeMillis()}")
}
btnSubmit2.clickThrottle(throttleTime = 1000L) {
Log.e("TAG", "click-throttle-${System.currentTimeMillis()}")
}