(代碼基於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實現防重複點擊,代碼可閱讀性和維護都變得簡單,但也有劣勢,增加了很多無用對象的創建。