这是一个很常见的需求,那么到底有多少种方案,每种各有什么特点?
更多问答 >>
-
2019-09-25 21:58
-
玩Android更新记录 [from 2019-10-02]
2019-10-08 21:44 -
2019-10-15 23:26
-
2019-10-20 23:46
-
2019-10-23 00:10
-
2019-09-17 22:41
-
2019-09-15 23:30
-
每日一问 gradle项目构建,需要经历哪些核心task,整个构建流程哪些我们可以干涉?
2019-09-15 23:29 -
2019-09-11 00:24
-
2019-09-09 00:19
基本的判断逻辑,能想到的有三种,分别是:
每次计算最后点击时间与当前时间的间隔,并判断是否超过指定时长。这种方法也是最最常见的;
@少東同学 举例的ButterKnife,它原理也很简单,就是:必须要等上一次事件处理完成之后,才接受新的事件(用flag标记,事件处理期间忽略多余的事件)。
借助线程池的延迟执行机制:每次处理事件之前,根据一个flag来判断应不应该处理该事件,当接收了事件之后,把这个flag标记为无效。事件处理完成后,向线程池提交一个延时执行的任务,这个任务就是把flag重新标记为可用,延时的时长,就是我们指定的间隔时长。所以,在指定的间隔时长之内到达的事件,也是会被直接忽略掉的,直到延时任务被执行(flag被重新标记可以)后,才继续接收新的事件,周而复始。这也是Rxjava的throttleFirst操作符的原理。
至于 @15398865919同学 提到的Rxjava的debounce操作符,个人觉得用在这里不太合适,虽然它也能避免重复点击。为什么呢? 因为这个操作符的特点是:在指定时间内如果重复接收到事件,那么它等待的时间就会重置。 也就是说,如果给这个操作符设置了2秒,那么事件的间隔必须要超过2秒,才会处理,如果2秒内又有新的事件到达,那刚刚等待的时间就会重置,也就是要重新等待了。
这个操作符适合什么样的场景呢?比如一些播放器,它下面显示的SeekBar,一般是触摸屏幕的时候,它会显示出来,过了一定时间没有操作屏幕,他就会隐藏,如果期间一直有触摸屏幕,那么它也就一直显示。这种场景就很适合用debounce来做。上面那三种方案分别有什么特点呢?
在效果角度来看,1和3是一样的,它接受新事件的间隔,取决于你指定的时长。
而第2种,它就没有根据固定时间间隔,只要本次点击事件未处理完成,就会一直等待。所以,1和3是有可能多个事件被同时处理的,比如点击按钮子线程发起网络请求,这种情况下,如果网络请求时间比较长,当用户第二次按下按钮的时候,就有可能再次发起网络请求了。而第二种方案,就不会发生这个情况。
是的当初也考虑过 debounce 操作符,但是发现确实不合适
如果我是新人发现之前的老代码所有点击的地方都需要屏蔽连续点击,怎么样可以用最少的改动来做呢?
前段时间尝试了一下2方案,替换1方案,1方案会导致列表滑动卡顿。。。 aspectj遇到的问题首先是如果不记录上次点击的id,直接判断两次点击的间隔会导致“在view的点击事件中调用另一个view的p ...查看更多
前段时间尝试了一下2方案,替换1方案,1方案会导致列表滑动卡顿。。。 aspectj遇到的问题首先是如果不记录上次点击的id,直接判断两次点击的间隔会导致“在view的点击事件中调用另一个view的performclick”被拦截过滤掉,如果记录上次点击的id,怎么保证上上次的id与当次的间隔呢。。。除非每个都记录id和点击事件,挨个对比,太麻烦了。 不使用3方案是因为需要更改的地方太多
可以将点击时间存在View的tag属性里(相当于你说的“除非每个都记录id和点击事件,挨个对比”),你每次只要对比当前 View 的 tag 属性即可。为 null 就是第一次点击啦,此后每次点击都判 ...查看更多
可以将点击时间存在View的tag属性里(相当于你说的“除非每个都记录id和点击事件,挨个对比”),你每次只要对比当前 View 的 tag 属性即可。为 null 就是第一次点击啦,此后每次点击都判断 tag 属性,如果超过目标间隔(如 1s),就分发事件,并重新设置 tag 值。 为避免 tag id 冲突,需要使用 R.id 详细:《Android | 使用 AspectJ 限制按钮快速点击》https://www.jianshu.com/p/018a838f8fe8,有用请点赞关注哦
屏蔽连续点击最好的办法就是增加响应速度,连击最快的时间都超过了50毫秒,50毫秒足够做出最快的响应了。而不是判断连击,屏蔽掉第二次点击。
确实需要提高响应速度,但是一些情况下没办法,比如一个发起网络请求的按钮
发起网络请求弹出提示框
50ms??一个最简单的空白页面的demo跳转页面都需要50毫秒。50能做什么
这种需求常见于点击按钮启动Activity的场景,startActivity最终会调用 startActivityForResult,所以比较简单实用的一种方案是:重写startActivityForResult,判断两次点击时间差
在陈小缘同学的基础上再加一种处理方式-----rxBinding,具体代码如下:推荐使用这个,简单方便
addDisposable(RxView.clicks(btnClick) .throttleFirst(2, TimeUnit.SECONDS) .subscribe(o -> { Log.e("rx_binding_test", "clicks:点击了按钮:两秒内防抖"); }));RxBinding中主要包含RxView、RxTextView、RxAdapterView、RxCompoundButton等等,由于内容太多,详细的源码可以参考Jake Wharton的RxBinding 地址为https://github.com/JakeWharton/RxBindingrxbinding debounce操作符
1.aspectj,直接对OnclickListener做处理
2.检查view树,设置了点击的就给那个点击换一个,然后添加视图树改变的监听,改变了就重来次(防止动态添加view)对于打开一个页面的连续点击不用理会。
对于处理业务逻辑的连续点击,加一个 flag,连续点击时,flag肯定是相同的,每次响应点击之前判断集合中是否存在该flag,不存在就把flag存放进事件集合,存在就取消该事件,此时取消的是上一次的点击事件,只处理这一次的事件。时间戳 每次点击都记录一次时间戳用静态变量存起来 两次时间戳只差<50ms 就忽略本次点击
butterknife 好像可以解决,哪位大神知道原理,以下是源码:
static boolean enabled = true;enabled用来做标志位,true的时候才能做点击事件 v.post(ENABLE_AGAIN);把翻转的操作放到viewroot的han ...查看更多
static boolean enabled = true;enabled用来做标志位,true的时候才能做点击事件 v.post(ENABLE_AGAIN);把翻转的操作放到viewroot的handler去处理 后面跟着实际操作 如果实际操作是用工作线程去做,而且时间比较长,是不是不能实现屏蔽连续点击? 只要处理了ENABLE_AGAIN,又能点击了。 为啥不是 v.postDelayed(ENABLE_AGAIN,100);来个大神吧。。。我好像不懂
我觉得这个得看具体的业务场景,一般我们点击一个按钮用工作线程执行,是发送一个异步请求,发送请求一般会弹出一个等待框,或者类似让按钮不能再次点的举措。