(代码基于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实现防重复点击,代码可阅读性和维护都变得简单,但也有劣势,增加了很多无用对象的创建。