1. 程式人生 > >Android 按鍵防止過快點選(防抖),在ButterKnife中的簡單解決方案。

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<OneClickUtil> 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事件的方法已經不推薦使用了,但是在一些比較簡單的情況,為了方便,又何嘗不可呢。