如何使用 RxJava 降低按钮点击事件的发生率?

How to use RxJava to decrease the rate of events generated by button's tap?

QA 团队执行的一项测试是疯狂点击某个按钮以确保只会执行一个事件。是否可以使用 RxJava 来确保这种行为?我试过从 RxJava 中读取 this backpressure page 但我发现这真的很难理解。另外,我看不出如何从按钮的 onClickListener 发出事件 - 我认为最终会创建一个新的观察者而不是发出新事件。

实现它的最简单方法是限制事件。您可以使用 throttleFirst operator:您基本上定义了一个 window,其中只会触发一个事件。

如果你使用 RxBinding library,你可以通过点击创建一个流,你可以有类似的东西:

RxView.clicks(button).throttleFirst(600, TimeUnit.MILLISECONDS)
    .subscribe(empty -> { // your action});

因此,在您单击按钮后的 600 毫秒内,任何其他单击都不会执行任何操作,并且您可以防止双重操作。

编辑:如果您不能使用 RxBinding,您可以通过这种方式创建您自己的 Observable

Observable<View> clickEventObservable = Observable.create(new Observable.OnSubscribe<View>() {
        @Override
        public void call(final Subscriber<? super View> subscriber) {
            mButton.setOnClickListener(v -> {
                if (subscriber.isUnsubscribed()) return;
                subscriber.onNext(v);
            });
        }
    });

注意:这个实现是针对 RxJava 1 的,但是你应该避免它(你不应该使用 create 在 RxJava 1 中创建一个 Observable ),但你可以使用 RxJava 2,其中使用 create 完全没问题。

为此您不需要使用 RxJava,您可以简单地使用实例变量作为指示器,使用它您可以检查上一次点击的动作是否正在进行,如果是则忽略事件。

我会混合使用 debounce() 以仅在用户完成输入后触发。然后只接受 first() 事件并保持订阅 repeat()。最后两个一起将确保您的点击事件在可以观察到另一个点击事件之前得到处理。

RxView.clicks(button)
      .debounce(300, TimeUnit.MILLISECONDS)
      .first()
      .repeat()
      .subscribe();

您只需要自行取消订阅此 Observable,也许可以使用 repeatWhen(),因为完成不会再取消订阅。