RxJava防重複點擊原理

(代碼基於rxbinding-1.0.1)
使用RxJava實現View防重複點擊功能比較簡單

fun View.noDoubleClick(action: Action1<Void>) {
    @Suppress("DEPRECATION")
    RxView.clicks(this)
            .throttleFirst(400, TimeUnit.MILLISECONDS)
            .subscribe(action, Action1 { t -> t.printStackTrace() })
}

它的原理是什麼呢?
首先看RxView.clicks(View)

@CheckResult @NonNull
public static Observable<Void> clicks(@NonNull View view) {
  checkNotNull(view, "view == null");
  return Observable.create(new ViewClickOnSubscribe(view));
}

只是將View封裝在ViewClickOnSubscribe裏,看下ViewClickOnSubscribe

final class ViewClickOnSubscribe implements Observable.OnSubscribe<Void> {
  final View view;

  ViewClickOnSubscribe(View view) {
    this.view = view;
  }

  @Override public void call(final Subscriber<? super Void> subscriber) {
       // ...省略不相干代碼

    View.OnClickListener listener = new View.OnClickListener() {
      @Override public void onClick(View v) {
        if (!subscriber.isUnsubscribed()) {
          subscriber.onNext(null);
        }
      }
    };
   // ...省略不相干代碼
    view.setOnClickListener(listener);
  }
}

只是設置了View的OnClickListener,點擊時這個listener對subscriber進行了調用。
看下傳入的subscriber,

.throttleFirst(400, TimeUnit.MILLISECONDS)
            .subscribe(action, Action1 { t -> t.printStackTrace() })

是經過throttleFirst的action,看下throttleFirst(long windowDuration, TimeUnit unit)

public final Observable<T> throttleFirst(long windowDuration, TimeUnit unit) {
    return throttleFirst(windowDuration, unit, Schedulers.computation());
}

直接調用了它的重名函數

public final Observable<T> throttleFirst(long skipDuration, TimeUnit unit, Scheduler scheduler) {
    return lift(new OperatorThrottleFirst<T>(skipDuration, unit, scheduler));
}

主要代碼應該在OperatorThrottleFirst裏,果然,記錄了每次onNext()執行的時間戳,若本次call執行的時間與上次執行onNext()的時間差值小於限定值,則不會調用onNext()。

public final class OperatorThrottleFirst<T> implements Operator<T, T> {

    final long timeInMilliseconds;
    final Scheduler scheduler;

    public OperatorThrottleFirst(long windowDuration, TimeUnit unit, Scheduler scheduler) {
        this.timeInMilliseconds = unit.toMillis(windowDuration);
        this.scheduler = scheduler;
    }

    @Override
    public Subscriber<? super T> call(final Subscriber<? super T> subscriber) {
        return new Subscriber<T>(subscriber) {

            private long lastOnNext = -1;

            @Override
            public void onStart() {
                request(Long.MAX_VALUE);
            }

            @Override
            public void onNext(T v) {
                long now = scheduler.now();
                if (lastOnNext == -1 || now < lastOnNext || now - lastOnNext >= timeInMilliseconds) {
                    lastOnNext = now;
                    subscriber.onNext(v);
                }
            }

            @Override
            public void onCompleted() {
                subscriber.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }

        };
    }
}

使用RxJava實現防重複點擊,代碼可閱讀性和維護都變得簡單,但也有劣勢,增加了很多無用對象的創建。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章