The following uses throttleWithTimeOut to filter out the Observable. We set the filtering time to 200 milliseconds. That is to say, data with an interval less than 200 milliseconds will be filtered out.
- private Observable<Integer> throttleWithTimeoutObserver() {
- return createObserver().throttleWithTimeout(200, TimeUnit.MILLISECONDS)
- .observeOn(AndroidSchedulers.mainThread());
- }
Subscribe to it
- mLButton.setText("throttleWithTimeout");
- mLButton.setOnClickListener(e -> throttleWithTimeoutObserver().subscribe(i -> log("throttleWithTimeout:" + i)));
The running result is as follows. We can see that new data is generated within 200 milliseconds after the data is not a multiple of 3, so it is filtered out.
The debounce operator can also use time for filtering. In this case, it is used in the same way as throttleWithTimeOut, but the deounce operator can also throttling based on a function. The returned value of this function is a temporary Observable. If the source Observable transmits a new data, the previous data is not completed yet according to the temporary Observable generated by the function, the previous data will be filtered out.
Generate an Observable and use debounce to filter it. The onCompleted method is called only when the transmitted data is an even number to indicate that the temporary Observable has been terminated.
- private Observable<Integer> debounceObserver() {
- return Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9).debounce(integer -> {
- log(integer);
- return Observable.create(new Observable.OnSubscribe<Integer>() {
- @Override
- public void call(Subscriber<? super Integer> subscriber) {
- if (integer % 2 == 0 && !subscriber.isUnsubscribed()) {
- log("complete:" + integer);
- subscriber.onNext(integer);
- subscriber.onCompleted();
- }
- }
- });
- })
- .observeOn(AndroidSchedulers.mainThread());
- }
Subscribe to it
- mRButton.setOnClickListener(e -> debounceObserver().subscribe(i -> log("debounce:" + i)));
The running result is as follows. We can see that only the data that calls the onCompleted method will be sent out, and the other data will be filtered out.
Ii. Distinct
The Distinct operator is used to remove duplicates, which is easy to understand. As shown in, all duplicate data will be filtered out. Another operator, distinctUntilChanged, is used to filter out consecutive duplicate data.
Create two Observable instances and filter them by using the Distinct and DistinctUtilChanged operators.
- private Observable<Integer> distinctObserver() {
- return Observable.just(1, 2, 3, 4, 5, 4, 3, 2, 1).distinct();
- }
- private Observable<Integer> distinctUntilChangedObserver() {
- return Observable.just(1, 2, 3, 3, 3, 1, 2, 3, 3).distinctUntilChanged();
- }
Subscribe
- mLButton.setText("distinct");
- mLButton.setOnClickListener(e -> distinctObserver().subscribe(i -> log("distinct:" + i)));
- mRButton.setText("UntilChanged");
- mRButton.setOnClickListener(e -> distinctUntilChangedObserver().subscribe(i -> log("UntilChanged:" + i)));
The running result is as follows. We can see that Distinct filters out all duplicate numbers, and DistinctUtilChanged filters out duplicate numbers only.
3. ElementAt and Filter
These two operators are well understood. ElementAt only returns data at the specified position, while Filter only returns data that meets the filtering conditions, as shown below:
Create two Observable objects and use the ElementAt and Filter operators to Filter them.
- private Observable<Integer> elementAtObserver() {
- return Observable.just(0, 1, 2, 3, 4, 5).elementAt(2);
- }
- private Observable<Integer> FilterObserver() {
- return Observable.just(0, 1, 2, 3, 4, 5).filter(i -> i < 3);
- }
Subscribe to them separately
- mLButton.setText("elementAt");
- mLButton.setOnClickListener(e -> elementAtObserver().subscribe(i -> log("elementAt:" + i)));
- mRButton.setText("Filter");
- mRButton.setOnClickListener(e -> FilterObserver().subscribe(i -> log("Filter:" + i)));
The running result is as follows:
4. First and Last
The First operator returns only the First data and the First data that meets the conditions. If you have read my previous blog, you will find that in our example of using Rxjava to implement a third-level cache, we use the first operator to select the cache to be used. In contrast to the First operator, the Last operator returns only the data that meets the conditions.
There is also a BlockingObservable method, which does not process Observable, but blocks it. When data that meets the conditions is sent out, a BlockingObservable object is returned. AvailableObservable.toBlockingOrBlockingObservable.fromMethod to convert an Observable object to a BlockingObservable object. BlockingObservable can be used with the first operator.
Create two Observable objects and use the first operator for processing.
- private Observable<Integer> FirstObserver() {
- return Observable.just(0, 1, 2, 3, 4, 5).first(i -> i > 1);
- }
- private BlockingObservable<Integer> FilterObserver() {
- return Observable.create(new Observable.OnSubscribe<Integer>() {
- @Override
- public void call(Subscriber<? super Integer> subscriber) {
- for (int i = 0; i < 5; i++) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if (!subscriber.isUnsubscribed()) {
- log("onNext:" + i);
- subscriber.onNext(i);
- }
- }
- if (!subscriber.isUnsubscribed()) {
- subscriber.onCompleted();
- }
- }
- }).toBlocking();
- }
Subscribe separately
- mLButton.setText("First");
- mLButton.setOnClickListener(e -> FirstObserver().subscribe(i -> log("First:" + i)));
- mRButton.setText(" Blocking");
- mRButton.setOnClickListener(e -> {
- log("blocking:" + FilterObserver().first(i -> i > 1));
- });
The running result is as follows. We can see that the first operator returns the first number 2 greater than 1, while BlockingObservable blocks until the first data greater than 1 is released.
V. Skip and Take
The Skip operator filters out the first n items of data transmitted by the source Observable, while the Take operator takes only the first n items. It is easy to understand and use, but it is very useful. In addition, there are SkipLast and TakeLast operators, respectively, from the back of the filter operation.
Create two Observable instances and use the skip and take operators to filter them.
- private Observable<Integer> skipObserver() {
- return Observable.just(0, 1, 2, 3, 4, 5).skip(2);
- }
- private Observable<Integer> takeObserver() {
- return Observable.just(0, 1, 2, 3, 4, 5).take(2);
- }
Subscribe separately
- mLButton.setText("Skip");
- mLButton.setOnClickListener(e -> skipObserver().subscribe(i -> log("Skip:" + i)));
- mRButton.setText("Take");
- mRButton.setOnClickListener(e -> takeObserver().subscribe(i -> log("Take:" + i)));
The running result is as follows. You can see that skip filters out the first two items, while take filters out all the items except the first two items.
6. Sample and ThrottleFirst
The Sample operator periodically transmits the data recently released by the source Observable. Other data will be filtered out, which is equivalent to the ThrottleLast operator. The ThrottleFirst operator periodically transmits the first data transmitted by the source Observable during this time period.
We create an Observable to send a data every 200 milliseconds, and then use the sample and throttleFirst operators to filter the data.
- private Observable<Integer> sampleObserver() {
- return createObserver().sample(1000, TimeUnit.MILLISECONDS);
- }
- private Observable<Integer> throttleFirstObserver() {
- return createObserver().throttleFirst(1000, TimeUnit.MILLISECONDS);
- }
- private Observable<Integer> createObserver() {
- return Observable.create(new Observable.OnSubscribe<Integer>() {
- @Override
- public void call(Subscriber<? super Integer> subscriber) {
- for (int i = 0; i < 20; i++) {
- try {
- Thread.sleep(200);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- subscriber.onNext(i);
- }
- subscriber.onCompleted();
- }
- });
- }
Subscribe separately
- mLButton.setText("sample");
- mLButton.setOnClickListener(e -> sampleObserver().subscribe(i -> log("sample:" + i)));
- mRButton.setText("throttleFirst");
- mRButton.setOnClickListener(e -> throttleFirstObserver().subscribe(i -> log("throttleFirst:" + i)));
The running result is as follows. We can see that the sample operator emits a data packet every five digits, while the throttleFirst operator emits the first data packet every five digits.
The demo program of this article see github: https://github.com/Chaoba/RxJavaDemo