Skip to content

Instantly share code, notes, and snippets.

@hilfritz
Last active November 6, 2024 16:19
Show Gist options
  • Save hilfritz/5a8ca9e172918bc224f03c3dac9c39f3 to your computer and use it in GitHub Desktop.
Save hilfritz/5a8ca9e172918bc224f03c3dac9c39f3 to your computer and use it in GitHub Desktop.
Android OnClickListener Prevent multiple clicks
import android.view.View;
/**
* inspired and credits
* @see http://stackoverflow.com/questions/16534369/avoid-button-multiple-rapid-clicks
* A Debounced OnClickListener
* Rejects clicks that are too close together in time.
* This class is safe to use as an OnClickListener for multiple views, and will debounce each one separately.
* 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.
*
* inspired and credits from: https://stackoverflow.com/a/9950832
*/
public abstract class SafeOnClickListener implements View.OnClickListener {
private static long lastClickMs = 0;
private static final String TAG = "SafeOnClickListener";
private static long TOO_SOON_DURATION_MS = 700;
/**
* Override onOneClick() instead.
*/
@Override
public final void onClick(View v) {
long nowMs = System.currentTimeMillis();
if (lastClickMs!=0 && (nowMs - lastClickMs) < TOO_SOON_DURATION_MS){
Log.d(TAG, "onClick: too soon");
return;
}
Log.d(TAG, "onClick: Ok");
lastClickMs = nowMs;
onOneClick(v);
}
public static final boolean isInteractionTooSoon(){
boolean retVal = false;
long nowMs = System.currentTimeMillis();
if (lastClickMs!=0 && (nowMs - lastClickMs) < TOO_SOON_DURATION_MS){
//TOO SOON
retVal = true;
}
return retVal;
}
/**
* 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);
}
///////USAGE
view.findViewById(R.id.cancelBtn).setOnClickListener(new SafeOnClickListener() {
@Override
public void onOneClick(View v) {
//DO SOMETHING
}
});
@Rvelazquez92
Copy link

Rvelazquez92 commented Nov 6, 2024

“Thanks for this class; you helped a lot. I recreated this class in Kotlin, and I’ll share it along with some extension functions for Android in Kotlin.”

abstract class SafeOnClickListener : View.OnClickListener {

    companion object {
        private var lastClickMs: Long = 0
        private const val TAG = "mx.com.suburbia.kiosko.ui.reprinttickets.SafeOnClickListener"
        private const val TOO_SOON_DURATION_MS: Long = 700

        fun isInteractionTooSoon(): Boolean {
            val nowMs = System.currentTimeMillis()
            return lastClickMs != 0L && (nowMs - lastClickMs) < TOO_SOON_DURATION_MS
        }
    }

    override fun onClick(v: View?) {
        val nowMs = System.currentTimeMillis()
        if (lastClickMs != 0L && (nowMs - lastClickMs) < TOO_SOON_DURATION_MS) {
            Log.d(TAG, "onClick: too soon")
            return
        }
        Log.d(TAG, "onClick: Ok")
        lastClickMs = nowMs
        onOneClick(v)
    }

    /**
     * Implementa esta función para manejar el evento de clic.
     */
    abstract fun onOneClick(v: View?)
}

Extension

fun View.setSafeOnClickListener(onSafeClick: (View?) -> Unit) {
    this.setOnClickListener(object : SafeOnClickListener() {
        override fun onOneClick(v: View?) {
            onSafeClick(v) // Llamada a la acción segura definida en la extensión
        }
    })
}

Use

binding.reprintTicketsDateRangeEditText.setSafeOnClickListener { view ->
   view?.let { showDatePicker() }
 }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment