网上大多数的解决方案都是设置一个延迟时间,但是使用过的人都知道,这个方案其实并不怎么好用.而且从代码上讲,这也只是一个治现象而不治本的方案
在解决问题前需要先要知道 为什么会触发重复点击
先来个日志:
可以看到:
即使主线程处于阻塞状态,app依然可以接收到触摸事件,而重复点击的根源就来自于这里!!!
为什么会这样呢?因为,触摸事件的接收线程不在自己app的主线程,而在于其它的进程,即使app主线程阻塞,当阻塞完成时,依然会收到并处理其它进程发送过来的触摸事件,而重复点击就出现在阻塞的时候.
先补充一个知识点:
onClick事件并不是在触摸事件中执行的,而是被抛到messageQueue中执行的!!!
大致画下click1点击后的时间图:
当搞清重复点击事件产生的原因后,解决方案就有了.
先上代码:
再上使用后的效果图:
原理就先不讲了,因为如果阻塞发生在当前点击事件中依然是有问题的,所以接下来讲更重要的问题.
先看bug图:
再上解决方案.其实再第一种解决方案中已经截出来了,就是注释的部分,但是我进一步测试后发现还是有bug,因为在下,下 次message执行前并不能保证系统已完全执行完所有阻塞的触摸事件,然后就只能祭出延时大法了,不过不需要使用夸张的几百ms,只需十几ms就可以了,比如我设置的16ms就基本上够用了,想必这也是一个非常好的值.
上代码,这次直接上同时控制两个控件组合的防重复点击
最后上解决方案的原理图:
到这里,我们已经解决了一种情况的重复点击问题。
即:主线程阻塞引起的重复点击
当然还有一种重复点击问题,也是最重要的,就是activity多次被启动的问题。
这个问题在模拟器中测试不出来,接下来真机测试,然后依然是一段日志:
以华为手机为例,当A activity->onPause,B activity ->onResume后,A activity居然还能接收到触摸事件!!!
这个时间段是很长的,而且当B activity接手触摸事件时,已经经历了多次的message的转换,根本无法在合适的时机进行拦截和取消拦截。
所以我只能对onPause下手了,当activity调用onPause后居然还能接收触摸事件这本来就很不合理。而且这样处理起来貌似也没有任何的问题,所以就有了下面的解决方案:
相信没有什么需求会是在activity调用onPause后依然接收触摸事件,如果有那就再加个延迟来解除拦截,此时就可以直接加给1000ms的延迟都是无所谓的。