美文网首页
如何克服触摸事件过于频繁,或者鼠标事件过于频繁(防抖动)

如何克服触摸事件过于频繁,或者鼠标事件过于频繁(防抖动)

作者: 九风特 | 来源:发表于2022-01-13 13:12 被阅读0次

我们在实际开发中 经常会有这样的需求,希望一个刷新事件A 别来的太频繁,希望放缓它,平滑它,这样说可能比较抽象
我们结合实际说一下,比如我们收到任何触摸事件都要做一个比较复杂的操作,但这个复杂操作实际上只是刷新UI,并没有必要过于频繁
只要保证最后一次触摸事件不丢失刷新然后中间适量刷新就行了, 但如果你在onTouchEvent里去做刷新,当用户手指在屏幕滑动时,那刷新会特别的频繁,那怎么合理平滑的忽略中间的一些触摸事件呢?
你一定有自己的想法,什么timer了,线程了。 但讲道理如果考虑到通用性和性能以及正确性这些,你想写一个这种功能模块,并不简单的,有两个关键点,可控平滑,不丢失最后一次,move刷新只是举个例子
那其实还是挺头疼的,反正我在windows用c++模拟这个功能,虽然算是成功了,但总感觉太重,不敢保证正确(线程很重,开销大)
那么到了android 我用kotlin 发现有非常牛逼的办法 实现这个需求,思路就是利用协程,协程已经说了 是很轻的,正确性由系统保证,频率可控通过delay,我实测非常管事儿,思路就是做一个 touch event的 flow 然后有条件的侦测这个flow 就okay了,我把主题代码贴一下,学过kt协程才能看懂, 知识点: 协程--flow---channel
主体代码

    private val channelEvents = Channel<MotionEvent?>()//用于发送touch event的管道
    private var flow:Flow<MotionEvent?> = flow {//把event组成一个流
        while (true){
            val evt = channelEvents.receive()
            emit(evt)
        }
    }
...
        lifecycleScope.launchWhenStarted {
            flow.conflate().onEach {
                delay(200)//每200ms处理一次事件,可控哦
                textViewEvt.text = getV("x:${it?.x}, y:${it?.y}")//把事件显示出来,模拟复杂操作了
            }.launchIn(this)
        }
...
   override fun onTouchEvent(event: MotionEvent?): Boolean {
        lifecycleScope.launch { channelEvents.send(event) }
        return super.onTouchEvent(event)
    }

下面是整个MainActivity的代码

package com.sky.testcoroutine

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MotionEvent
import android.widget.TextView
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.*

class MainActivity : AppCompatActivity() {
    lateinit var txt: TextView
    lateinit var textViewEvt:TextView
    private val channelEvents = Channel<MotionEvent?>()
    private var flow:Flow<MotionEvent?> = flow {
        while (true){
            val evt = channelEvents.receive()
            emit(evt)
        }
    }
    private val startTime = System.currentTimeMillis()
    fun <T> log(v: T) {
        println("${Thread.currentThread().name}: $v")
    }
    private fun <T> getV(v:T) = "${System.currentTimeMillis()-startTime} ms ${Thread.currentThread().name}: $v"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        txt = findViewById(R.id.textLabel)
        textViewEvt = findViewById(R.id.textViewEvt)
        lifecycleScope.launchWhenStarted {
            flow.conflate().onEach {
                delay(200)
                textViewEvt.text = getV("x:${it?.x}, y:${it?.y}")
            }.launchIn(this)
        }
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        lifecycleScope.launch { channelEvents.send(event) }
        return super.onTouchEvent(event)
    }
}

这个代码要跑起来需要引入一些东西 协程 以及安卓的lifecycle,我都假设你已经会了,本文只是提供这个思路
如果非要一个完整的demo 可留言

相关文章

网友评论

      本文标题:如何克服触摸事件过于频繁,或者鼠标事件过于频繁(防抖动)

      本文链接:https://www.haomeiwen.com/subject/dkyncrtx.html