在安卓系统中防止双击按钮的最佳方法是什么?


当前回答

我的解决方案(Kotlin):

class OnDebouncedClickListener(private val delayInMilliSeconds: Long, val action: () -> Unit) : View.OnClickListener {
    var enable = true

    override fun onClick(view: View?) {
        if (enable) {
            enable = false
            view?.postDelayed(delayInMilliSeconds) { enable = true }
            action()
        }
    }
}

fun View.setOnDebouncedClickListener(delayInMilliSeconds: Long = 500, action: () -> Unit) {
    val onDebouncedClickListener = OnDebouncedClickListener(delayInMilliSeconds, action)
    setOnClickListener(onDebouncedClickListener)
}

使用:

button.apply {       
            setOnDebouncedClickListener {
                //your action on click
            }
        }

其他回答

如果你在onClick()中进行计算密集型工作,则禁用按钮或设置不可点击是不够的,因为单击事件可以在禁用按钮之前排队。我写了一个实现OnClickListener的抽象基类,你可以重写,通过忽略任何排队点击来修复这个问题:

/** 
 * This class allows a single click and prevents multiple clicks on
 * the same button in rapid succession. Setting unclickable is not enough
 * because click events may still be queued up.
 * 
 * Override onOneClick() to handle single clicks. Call reset() when you want to
 * accept another click.
 */
public abstract class OnOneOffClickListener implements OnClickListener {
    private boolean clickable = true;

    /**
     * Override onOneClick() instead.
     */
    @Override
    public final void onClick(View v) {
        if (clickable) {
            clickable = false;
            onOneClick(v);
            //reset(); // uncomment this line to reset automatically
        }
    }

    /**
     * Override this function to handle clicks.
     * reset() must be called after each click for this function to be called
     * again.
     * @param v
     */
    public abstract void onOneClick(View v);

    /**
     * Allows another click.
     */
    public void reset() {
        clickable = true;
    }
}

用法与OnClickListener相同,但重写OnOneClick()代替:

OnOneOffClickListener clickListener = new OnOneOffClickListener() {
    @Override
    public void onOneClick(View v) {

        // Do stuff

        this.reset(); // or you can reset somewhere else with clickListener.reset();
    }
};
myButton.setOnClickListener(clickListener);

Kotlin扩展,允许简洁的内联代码和变量双击等待时间

fun View.setDoubleClickListener(listener: View.OnClickListener, waitMillis : Long = 1000) {
    var lastClickTime = 0L
    setOnClickListener { view ->
        if (System.currentTimeMillis() > lastClickTime + waitMillis) {
            listener.onClick(view)
            lastClickTime = System.currentTimeMillis()
        }
    }
}

用法:

anyView.setNoDoubleClickListener(View.OnClickListener { v ->
    // do stuff
})

Or

anyView.setNoDoubleClickListener(View.OnClickListener { v ->
    // do stuff
}, 1500)

如果你不想(或不能)使用布尔标志或覆盖onClickListener,你也可以尝试用android:launchMode="singleTop"在AndroidManifest.xml声明你的活动。

它是如何工作的?

如果活动的实例位于堆栈顶部- new activity不会被创建,相反- onNewIntent()将被调用。 活动可以有多个实例 实例可以驻留在不同的任务中 一个任务可以有多个实例

Setting the button as clickable false upon clicking and true once it is desired to make the button clickable again is the right approach. For instance, consider the following scenario: you are making a service call upon click of a button and once the service is done you want to display a dialog. For this, once the button is clicked you can set setClickable(false) and once the service responds you will do setClicklable(true) through a reference you pass to your custom dialog. When dialog invokes isShowing() you can trigger the listener and setClicklable(true).

在点击的时候保存最后一次点击的时间可以避免这个问题。

i.e.

private long mLastClickTime = 0;

...

// inside onCreate or so:

findViewById(R.id.button).setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        // mis-clicking prevention, using threshold of 1000 ms
        if (SystemClock.elapsedRealtime() - mLastClickTime < 1000){
            return;
        }
        mLastClickTime = SystemClock.elapsedRealtime();

        // do your magic here
    }
}