RxJava operator (3) Filtering

Source: Internet
Author: User

RxJava operator (3) Filtering
In the previous article, we learned about conversion operators that can convert data into the desired format. But what if there is some data in the data set that we want to filter out? At this time, we need to use the filter operator, which is a bit similar to the where in SQL, so that the Observable only returns data that meets our conditions.

I. debounce
The debounce operator is used to throttling. It can be understood as a valve. When you open the valve halfway, the water will flow out at a slow speed. The difference is that the water in the valve will not be wasted, and the data filtered out by debounce will be discarded. In Rxjava, the operator atmosphere is changed.throttleWithTimeoutAndDebounce operator. Let's take a look at throttleWithTimeOut, as shown in. This operator throws traffic through time. The source Observable will start timing each time it emits a data, if a new data is sent from the source Observable before the set time ends, the data is discarded and the timing starts again. If data is transmitted before the end of each time, the throttling will go to the extreme: only the last data will be transmitted.


First, we will create an Observable to send data every 100 milliseconds. When the data to be transmitted is a multiple of 3, the next data will be delayed to 300 milliseconds before being transmitted.

 
 
  1. private Observable<Integer> createObserver() {
  2. return Observable.create(new Observable.OnSubscribe<Integer>() {
  3. @Override
  4. public void call(Subscriber<? super Integer> subscriber) {
  5. for (int i = 0; i < 10; i++) {
  6. if (!subscriber.isUnsubscribed()) {
  7. subscriber.onNext(i);
  8. }
  9. int sleep = 100;
  10. if (i % 3 == 0) {
  11. sleep = 300;
  12. }
  13. try {
  14. Thread.sleep(sleep);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }

  18. }
  19. subscriber.onCompleted();
  20. }
  21. }).subscribeOn(Schedulers.computation());
  22. }
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.

  
  
  1. private Observable<Integer> throttleWithTimeoutObserver() {
  2. return createObserver().throttleWithTimeout(200, TimeUnit.MILLISECONDS)
  3. .observeOn(AndroidSchedulers.mainThread());

  4. }
Subscribe to it

  
  
  1. mLButton.setText("throttleWithTimeout");
  2. 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.

  
  
  1. private Observable<Integer> debounceObserver() {
  2. return Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9).debounce(integer -> {
  3. log(integer);
  4. return Observable.create(new Observable.OnSubscribe<Integer>() {
  5. @Override
  6. public void call(Subscriber<? super Integer> subscriber) {
  7. if (integer % 2 == 0 && !subscriber.isUnsubscribed()) {
  8. log("complete:" + integer);
  9. subscriber.onNext(integer);
  10. subscriber.onCompleted();
  11. }
  12. }
  13. });
  14. })
  15. .observeOn(AndroidSchedulers.mainThread());
  16. }
Subscribe to it

  
  
  1. 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.

  
  
  1. private Observable<Integer> distinctObserver() {
  2. return Observable.just(1, 2, 3, 4, 5, 4, 3, 2, 1).distinct();

  3. }

  4. private Observable<Integer> distinctUntilChangedObserver() {
  5. return Observable.just(1, 2, 3, 3, 3, 1, 2, 3, 3).distinctUntilChanged();

  6. }
Subscribe

  
  
  1. mLButton.setText("distinct");
  2. mLButton.setOnClickListener(e -> distinctObserver().subscribe(i -> log("distinct:" + i)));
  3. mRButton.setText("UntilChanged");
  4. 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.

  
  
  1. private Observable<Integer> elementAtObserver() {
  2. return Observable.just(0, 1, 2, 3, 4, 5).elementAt(2);
  3. }

  4. private Observable<Integer> FilterObserver() {
  5. return Observable.just(0, 1, 2, 3, 4, 5).filter(i -> i < 3);
  6. }
Subscribe to them separately

  
  
  1. mLButton.setText("elementAt");
  2. mLButton.setOnClickListener(e -> elementAtObserver().subscribe(i -> log("elementAt:" + i)));
  3. mRButton.setText("Filter");
  4. 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.

  
  
  1. private Observable<Integer> FirstObserver() {
  2. return Observable.just(0, 1, 2, 3, 4, 5).first(i -> i > 1);
  3. }

  4. private BlockingObservable<Integer> FilterObserver() {
  5. return Observable.create(new Observable.OnSubscribe<Integer>() {
  6. @Override
  7. public void call(Subscriber<? super Integer> subscriber) {
  8. for (int i = 0; i < 5; i++) {
  9. try {
  10. Thread.sleep(500);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. if (!subscriber.isUnsubscribed()) {
  15. log("onNext:" + i);
  16. subscriber.onNext(i);
  17. }
  18. }
  19. if (!subscriber.isUnsubscribed()) {
  20. subscriber.onCompleted();
  21. }
  22. }
  23. }).toBlocking();
  24. }
Subscribe separately

  
  
  1. mLButton.setText("First");
  2. mLButton.setOnClickListener(e -> FirstObserver().subscribe(i -> log("First:" + i)));
  3. mRButton.setText(" Blocking");
  4. mRButton.setOnClickListener(e -> {
  5. log("blocking:" + FilterObserver().first(i -> i > 1));
  6. });
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.

  
  
  1. private Observable<Integer> skipObserver() {
  2. return Observable.just(0, 1, 2, 3, 4, 5).skip(2);
  3. }
  4. private Observable<Integer> takeObserver() {
  5. return Observable.just(0, 1, 2, 3, 4, 5).take(2);
  6. }
Subscribe separately

  
  
  1. mLButton.setText("Skip");
  2. mLButton.setOnClickListener(e -> skipObserver().subscribe(i -> log("Skip:" + i)));
  3. mRButton.setText("Take");
  4. 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.

  
  
  1. private Observable<Integer> sampleObserver() {
  2. return createObserver().sample(1000, TimeUnit.MILLISECONDS);
  3. }

  4. private Observable<Integer> throttleFirstObserver() {
  5. return createObserver().throttleFirst(1000, TimeUnit.MILLISECONDS);
  6. }


  7. private Observable<Integer> createObserver() {
  8. return Observable.create(new Observable.OnSubscribe<Integer>() {
  9. @Override
  10. public void call(Subscriber<? super Integer> subscriber) {
  11. for (int i = 0; i < 20; i++) {
  12. try {
  13. Thread.sleep(200);
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. subscriber.onNext(i);
  18. }
  19. subscriber.onCompleted();
  20. }
  21. });
  22. }
Subscribe separately

  
  
  1. mLButton.setText("sample");
  2. mLButton.setOnClickListener(e -> sampleObserver().subscribe(i -> log("sample:" + i)));
  3. mRButton.setText("throttleFirst");
  4. 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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.