I have a problem with my app that if the user clicks the button multiple times quickly, then multiple events are generated before even my dialog holding the button disappear
Here's my version of the accepted answer. It is very similar, but doesn't try to store Views in a Map which I don't think is such a good idea. It also adds a wrap method that could be useful in many situations.
/**
* Implementation of {@link OnClickListener} that ignores subsequent clicks that happen too quickly after the first one.<br/>
* To use this class, implement {@link #onSingleClick(View)} instead of {@link OnClickListener#onClick(View)}.
*/
public abstract class OnSingleClickListener implements OnClickListener {
private static final String TAG = OnSingleClickListener.class.getSimpleName();
private static final long MIN_DELAY_MS = 500;
private long mLastClickTime;
@Override
public final void onClick(View v) {
long lastClickTime = mLastClickTime;
long now = System.currentTimeMillis();
mLastClickTime = now;
if (now - lastClickTime < MIN_DELAY_MS) {
// Too fast: ignore
if (Config.LOGD) Log.d(TAG, "onClick Clicked too quickly: ignored");
} else {
// Register the click
onSingleClick(v);
}
}
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
public abstract void onSingleClick(View v);
/**
* Wraps an {@link OnClickListener} into an {@link OnSingleClickListener}.<br/>
* The argument's {@link OnClickListener#onClick(View)} method will be called when a single click is registered.
*
* @param onClickListener The listener to wrap.
* @return the wrapped listener.
*/
public static OnClickListener wrap(final OnClickListener onClickListener) {
return new OnSingleClickListener() {
@Override
public void onSingleClick(View v) {
onClickListener.onClick(v);
}
};
}
}
More significant way to handle this scenario is using Throttling operator (Throttle First) with RxJava2. Steps to achieve this in Kotlin :
1). Dependencies :- Add rxjava2 dependency in build.gradle app level file.
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation 'io.reactivex.rxjava2:rxjava:2.2.10'
2). Construct an abstract class that implements View.OnClickListener & contains throttle first operator to handle the view’s OnClick() method. Code snippet is as:
import android.util.Log
import android.view.View
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.subjects.PublishSubject
import java.util.concurrent.TimeUnit
abstract class SingleClickListener : View.OnClickListener {
private val publishSubject: PublishSubject<View> = PublishSubject.create()
private val THRESHOLD_MILLIS: Long = 600L
abstract fun onClicked(v: View)
override fun onClick(p0: View?) {
if (p0 != null) {
Log.d("Tag", "Clicked occurred")
publishSubject.onNext(p0)
}
}
init {
publishSubject.throttleFirst(THRESHOLD_MILLIS, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe { v -> onClicked(v) }
}
}
3). Implement this SingleClickListener class on the click of view in activity. This can be achieved as :
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val singleClickListener = object : SingleClickListener(){
override fun onClicked(v: View) {
// operation on click of xm_view_id
}
}
xm_viewl_id.setOnClickListener(singleClickListener)
}
Implementing these above steps into the app can simply avoid the multiple clicks on a view till 600mS. Happy coding!