Android 按键防止过快点击(防抖),在ButterKnife中的简单解决方案。

其实自己也在网上找了一些防抖的方案,比如RxBinding啊,NoDoubleClickListener啊,原始解决方案啊等等,不过那都不是我想要的。
因为项目中使用了ButterKnife绑定控件和为控件注册点击事件。所以上面搜到的那些方案都不太好使,原始的又过于臃肿。
最后还是只能自己动手丰衣足食了。
其实想要防抖无非就是判断一下时间差,但每次写一堆代码,或者说每次复制一堆代码,很臃肿,我是很讨厌这种体验的。

我心中最理想的解决方案是,在每个Click方法第一行加入

    if (ClickUtil.check()) return;

虽然这种也实现了, 但是涉及到静态变量的保存,所有对象都作为静态变量保存到内存中,这样还是不太好的,如果整个项目需要绑定的事件一多到最后肯定效率越来越低。所以综合考虑了一下,最后废弃了这种使用静态方法来检查的思路。

现在的使用方法是,首先声明一个全局的util变量。

    AntiShake util = new AntiShake();

然后在每个Click方法第一行加入

    if (util.check()) return;

就可以实现防抖的目的了。是不是非常方便呢,现在我们来贴一下实现的代码吧。
一共是两个类。
第一个OneClickUtil.java

public class OneClickUtil {
    private String methodName;
    public static final int MIN_CLICK_DELAY_TIME = 1000;
    private long lastClickTime = 0;

    public OneClickUtil(String methodName) {
        this.methodName = methodName;
    }

    public String getMethodName() {
        return methodName;
    }

    public boolean check() {
        long currentTime = Calendar.getInstance().getTimeInMillis();
        if (currentTime - lastClickTime > MIN_CLICK_DELAY_TIME) {
            lastClickTime = currentTime;
            return false;
        } else {
            return true;
        }
    }
}

第二个AntiShake.java

public class AntiShake {
    private List utils = new ArrayList<>();

    public boolean check(Object o) {
        String flag = null;
        if(o == null)
            flag = Thread.currentThread().getStackTrace()[2].getMethodName();
        else
            flag = o.toString();
        for (OneClickUtil util : utils) {
            if (util.getMethodName().equals(flag)) {
                return util.check();
            }
        }
        OneClickUtil clickUtil = new OneClickUtil(flag);
        utils.add(clickUtil);
        return clickUtil.check();
    }

    public boolean check() {
        return check(null);
    }
}

代码贴出来了,相信思路也非常容易理解,不过我还是简单讲一下吧。
首先使用OneClickUtil 保存点击事件的lastClickTime。并且实现一个check方法。
然后AntiShake主要是保存这些OneClickUtil对象,并且为他们设置不同的标识,标识为不同的点击事件,同时标识也可以由用户传入,这样可以处理一些特殊情况,后面会讲解。
在AntiShake中,我使用的是 “调用check方法的上级方法名”来做标识,简单的说,我在click方法中调用了这个check方法,我就使用“click”字符串来作为对象标识。

在文章开头的那种使用方法仅适用于每个点击事件对应一个方法的情况,那如果有多个id都被绑在同一个方法上,那么使用同一个方法名作为标识就不太合理了。这种情况的使用方法,应如下:

    @OnClick({R.id.btn1,R.id.btn2,R.id.btn3})
    public void click(View view) {
        if(util.check(view.getId())) return;
    }

也就是手动传入标识,是不是也非常方便呢。同时在xml中为控件配置Onclick对应方法的,也可以使用这种方式来防止重复点击,虽然这种配置Onclick事件的方法已经不推荐使用了,但是在一些比较简单的情况,为了方便,又何尝不可呢。

你可能感兴趣的:(Android)