问题
I'm trying to make a simple "button debouncer" which will count filtered clicks and display it thru a TextView. I want to filter rapid/spam clicks in a way that clicks with less than 300ms time-gap in-between are ignored.
I did my research and stumbled upon Rx
's awesome debounce()
which in theory should do the exact thing I wanted..
..or so I thought. As the app seemed to only register the first click; the counter won't increment no matter how long I tried to wait.
Here's a piece of my code:
...
RxView.clicks(mButton)
.debounce(300, TimeUnit.MILLISECONDS)
.subscribe(new Subscriber<Object>() {
public int mCount;
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Object o) {
mText.setText(String.valueOf(++mCount));
}
});
...
What am I doing wrong? I've tried to run the thing without debounce()
and it worked flawlessly (the counter will increment everytime the button got clicked).
Thanks in advance!
回答1:
Note the following in the documentation on the debounce operator:
This variant operates by default on the computation Scheduler (...)
Or, code-wise, this currently happens:
public final Observable<T> debounce(long timeout, TimeUnit unit) {
return debounce(timeout, unit, Schedulers.computation());
}
As a result, the subscriber's callbacks are invoked on that same computation scheduler, since nothing is explicitly instructing otherwise.
Now, attempting to update a view (that's what's happening in onNext()
) from any other thread than the main/ui thread, is a mistake and it will lead to undetermined results.
Fortunately, the remainder of the quote above provides the solution too:
(...) but you can optionally pass in a Scheduler of your choosing as a third parameter.
This would lead to:
RxView.clicks(mButton)
.debounce(300, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.subscribe(...);
Alternatively, you can still let the debounce happen on the computation scheduler, but receive the notifications on the main/ui thread:
RxView.clicks(mButton)
.debounce(300, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
Either way will ensure that the notifications are received on the main/ui thread and thus that the view is updated from the correct thread.
来源:https://stackoverflow.com/questions/32498210/debouncing-button-clicks-using-rx