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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值