Evita il button multipli clic rapidi

Ho un problema con la mia applicazione che se l'utente fa clic sul button più volte in modo rapido, vengono generati più events prima che anche la window di dialogo contenente il button scompare

Conosco una soluzione impostando una variabile booleana come bandiera quando un button viene cliccato in modo che i clic futuri possano essere evitati finché la window di dialogo non viene chiusa. Tuttavia ho molti pulsanti e dovrai farlo each volta che each bottone sembra essere un sovraccarico. Non esiste altro modo in android (o forse una soluzione più intelligente) per consentire solo un'azione di evento generata per clic del button?

  • Vista trasparente sfocata che sfuma il layout sotto
  • Tentativo di riaprire un sqlitedatabase di un object già chiuso
  • Il codice codice_key non viene chiamato ANDROID
  • Android - OnClick all'interno della row di gridview
  • Come get l'authorization di un'app per each applicazione? come farlo in modo programmato su Android?
  • aggiornamento di programmazione android Vector Disegnabile
  • Quello che è ancora peggiore è che molti clic rapidi sembrano generare un'azione multipla di events prima che anche la prima azione venga gestita, quindi se voglio distriggersre il button nel primo metodo di gestione dei clic, ci sono azioni già esistenti nella coda in attesa di essere gestite!

    Aiuti prego grazie

    9 Solutions collect form web for “Evita il button multipli clic rapidi”

    Ecco un ascoltatore onClick debuffato che ho scritto di recente. Ti dici che è il numero minima accettabile di millisecondi tra i clic. Implementa la tua logica in onDebouncedClick invece di onClick

     import android.os.SystemClock; import android.view.View; import java.util.Map; import java.util.WeakHashMap; /** * 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. */ public abstract class DebouncedOnClickListener implements View.OnClickListener { private final long minimumInterval; private Map<View, Long> lastClickMap; /** * Implement this in your subclass instead of onClick * @param v The view that was clicked */ public abstract void onDebouncedClick(View v); /** * The one and only constructor * @param minimumIntervalMsec The minimum allowed time between clicks - any click sooner than this after a previous click will be rejected */ public DebouncedOnClickListener(long minimumIntervalMsec) { this.minimumInterval = minimumIntervalMsec; this.lastClickMap = new WeakHashMap<View, Long>(); } @Override public void onClick(View clickedView) { Long previousClickTimestamp = lastClickMap.get(clickedView); long currentTimestamp = SystemClock.uptimeMillis(); lastClickMap.put(clickedView, currentTimestamp); if(previousClickTimestamp == null || (currentTimestamp - previousClickTimestamp.longValue() > minimumInterval)) { onDebouncedClick(clickedView); } } } 

    Con RxBinding può essere fatto facilmente. Ecco un esempio:

     RxView.clicks(view).throttleFirst(500, TimeUnit.MILLISECONDS).subscribe(empty -> { // action on click }); 

    Aggiungere la seguente row in build.gradle per aggiungere dipendenza RxBinding:

     compile 'com.jakewharton.rxbinding:rxbinding:0.3.0' 

    Ecco la mia versione della risposta accettata. È molto simile, ma non tenta di memorizzare le viste in una mappa che non credo sia una buona idea. Inoltre aggiunge un metodo di avvolgimento che potrebbe essere utile in molte situazioni.

     /** * 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); } }; } } 

    È ansible utilizzare questo progetto: https://github.com/fengdai/clickguard per risolvere questo problema con una sola istruzione:

     ClickGuard.guard(button); 

    Solo un aggiornamento rapido sulla soluzione GreyBeardedGeek. Modifica se clausola e aggiungere function Math.abs. Impostalo come questo:

      if(previousClickTimestamp == null || (Math.abs(currentTimestamp - previousClickTimestamp.longValue()) > minimumInterval)) { onDebouncedClick(clickedView); } 

    L'utente può modificare l'ora sul dispositivo Android e metterlo in passato, quindi senza questo potrebbe portre a un bug.

    PS: non hai abbastanza punti per commentare la tua soluzione, quindi ho appena messo un'altra risposta.

    Ecco un semplice esempio:

     public abstract class SingleClickListener implements View.OnClickListener { private static final long THRESHOLD_MILLIS = 1000L; private long lastClickMillis; @Override public void onClick(View v) { long now = SystemClock.elapsedRealtime(); if (now - lastClickMillis > THRESHOLD_MILLIS) { onClicked(v); } lastClickMillis = now; } public abstract void onClicked(View v); } 

    Soluzione simile con RxJava

     import android.view.View; import java.util.concurrent.TimeUnit; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; import rx.subjects.PublishSubject; public abstract class SingleClickListener implements View.OnClickListener { private static final long THRESHOLD_MILLIS = 600L; private final PublishSubject<View> viewPublishSubject = PublishSubject.<View>create(); public SingleClickListener() { viewPublishSubject.throttleFirst(THRESHOLD_MILLIS, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<View>() { @Override public void call(View view) { onClicked(view); } }); } @Override public void onClick(View v) { viewPublishSubject.onNext(v); } public abstract void onClicked(View v); } 

    Questo è risolto così

     Observable<Object> tapEventEmitter = _rxBus.toObserverable().share(); Observable<Object> debouncedEventEmitter = tapEventEmitter.debounce(1, TimeUnit.SECONDS); Observable<List<Object>> debouncedBufferEmitter = tapEventEmitter.buffer(debouncedEventEmitter); debouncedBufferEmitter.buffer(debouncedEventEmitter) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<List<Object>>() { @Override public void call(List<Object> taps) { _showTapCount(taps.size()); } }); 

    Ecco qualcosa che funziona con qualsiasi evento, non solo clic. Fornirà anche l'ultimo evento anche se fa parte di una serie di events veloci (come rx debounce ).

     class Debouncer(timeout: Long, unit: TimeUnit, fn: () -> Unit) { private val timeoutMillis = unit.toMillis(timeout) private var lastSpamMillis = 0L private val handler = Handler() private val runnable = Runnable { fn() } fun spam() { if (SystemClock.uptimeMillis() - lastSpamMillis < timeoutMillis) { handler.removeCallbacks(runnable) } handler.postDelayed(runnable, timeoutMillis) lastSpamMillis = SystemClock.uptimeMillis() } } // example view.addOnClickListener.setOnClickListener(object: View.OnClickListener { val debouncer = Debouncer(1, TimeUnit.SECONDS, { showSomething() }) override fun onClick(v: View?) { debouncer.spam() } }) 

    1) Costruire Debouncer in un field dell'ascoltatore ma al di fuori della function di richiamata, configurata con timeout e il richiamo fn che si desidera far girare.

    2) Chiama il metodo dello spam di Debouncer nella function di richiamata dell'ascoltatore.

    L'Android è un fan Android di Google, tutto su telefoni Android, Android Wear, Android Dev e applicazioni Android Games e così via.