RxJava Operator Series 3 (Part 1)

RxJava Operator Series 3 (Part 1)

RxJava Operator Series Portal

  • RxJava operator source code

https://github.com/xiehui999/fuseProgram

  • RxJava Operator Series 1
  • RxJava Operator Series 2

[[180583]]

Preface

In the previous article, we introduced some operators for creating Observables and converting data. Some of the operators for data conversion are still difficult to understand, but I believe that if you type the code once and modify the values ​​of various parameters and observe the execution log, it is still easy to understand. On the official website, each operator is given a legend. If you don’t understand the text clearly, you can also refer to the diagram to help yourself understand. In this article, we will introduce some common filter operators. Filter operators in RxJava are also relatively easy to understand. Okay, let’s continue our learning journey together.

Filter

This operator receives a Func1 parameter, in which we can use our own judgment conditions to judge the data we want to filter. When the data passes the judgment condition, it returns true to indicate that the data is emitted, otherwise it is not emitted, thus filtering out the data we want. As shown below, we filter out numbers that are not divisible by 2.

  1. Integer [] ints = {1, 2, 3, 4, 5, 6, 7, 8, 9};
  2.  
  3. Observable observable = Observable. from (ints).filter(new Func1< Integer , Boolean>() {
  4.  
  5. @Override
  6.  
  7. public Boolean call( Integer   integer ) {
  8.  
  9. return   integer % 2 != 0; //Return true , it will not be filtered out, the data will be emitted, and the value that returns false will be filtered out
  10.  
  11. }
  12.  
  13. });
  14.  
  15. Action1 action1 = new Action1< Integer >() {
  16.  
  17. @Override
  18.  
  19. public void call( Integer i) {
  20.  
  21. Log.e(TAG, "call: " +i );
  22.  
  23. }
  24.  
  25. };
  26.  
  27. observable.subscribe(action1);

Output log information

  1. call: 1
  2.  
  3. call: 3
  4.  
  5. call: 5
  6.  
  7. call: 7
  8.  
  9. call: 9

ofType

This operator is a special form of the filter operator. It filters an Observable to return only data of a specified type. For example, when the data source has string and int data, we can use this operator if we want to filter out the string, as shown in the following example code

  1. Observable.just(0, "one" , 6, 4, "two" , 8, "three" , 1, "four" , 0)
  2.  
  3. .ofType(String.class)
  4.  
  5. .subscribe(new Subscriber<String>() {
  6.  
  7. @Override
  8.  
  9. public void onCompleted() {
  10.  
  11. Log.e(TAG, "onCompleted:ofType " );
  12.  
  13. }
  14.  
  15.   
  16.  
  17. @Override
  18.  
  19. public void onError(Throwable e) {
  20.  
  21. Log.e(TAG, "onError:ofType " );
  22.  
  23. }
  24.  
  25.   
  26.  
  27. @Override
  28.  
  29. public void onNext(String string) {
  30.  
  31. Log.e(TAG, "onNext:ofType " + string);
  32.  
  33. }
  34.  
  35. });

Output log information

  1. onNext:ofType one
  2.  
  3. onNext:ofType two
  4.  
  5. onNext:ofType three
  6.  
  7. onNext:ofType four
  8.  
  9. onCompleted:ofType

Of course, in addition to filtering basic types of data, you can also filter custom types of data.

First

If we are only interested in the first item of data emitted by the Observable, or the first item of data that meets a certain condition, we can use the First operator.

  1. Observable.just(10, 11, 12, 13). first ().subscribe(new Action1() {
  2.  
  3. @Override
  4.  
  5. public void call( Integer   integer ) {
  6.  
  7. Log.e(TAG, integer + "" );
  8.  
  9. }
  10.  
  11. });

The above log only prints a value of 10. Of course, we can also pass a parameter Fun1 to first and specify a condition as follows

  1. Observable.just(10, 11, 12, 13). first (new Func1< Integer , Boolean>() {
  2.  
  3. @Override
  4.  
  5. public Boolean call( Integer   integer ) {
  6.  
  7. return   integer > 12;
  8.  
  9. }
  10.  
  11. }).subscribe(new Action1 <Integer> () {
  12.  
  13. @Override
  14.  
  15. public void call( Integer   integer ) {
  16.  
  17. Log.e(TAG, integer + "" );
  18.  
  19. }
  20.  
  21. });

The output information at this time is the first item of data 13 that satisfies integer > 12.

firstOrDefault

This operator is a variation of the first operator. It mainly emits a default value you specify in the parameter when no data is emitted. As shown below, it has two overloaded methods.

  1. Observable.just(11,12,13).firstOrDefault(10).subscribe(new Action1<Object>() {
  2.  
  3. @Override
  4.  
  5. public void call(Object o) {
  6.  
  7. Log.e(TAG, o.toString());
  8.  
  9. }
  10.  
  11. });

If the above code is written, the execution will have the same effect as the first one. Because the default value is used when no data is emitted, we change the above code as follows, using empty to create an Observable that does not emit any data but terminates normally.

  1. Observable.empty().firstOrDefault(10).subscribe(new Action1<Object>() {
  2.  
  3. @Override
  4.  
  5. public void call(Object o) {
  6.  
  7. Log.e(TAG, o.toString());
  8.  
  9. }
  10.  
  11. });

It is found that the data 10 is output at this time. The operator also provides an overloaded method firstOrDefault(T defaultValue, Func1 super T, Boolean> predicate) with two parameters. We can add a condition. The following example

  1. Observable.just(10, 13,16).firstOrDefault(15, new Func1< Integer , Boolean>() {
  2.  
  3. @Override
  4.  
  5. public Boolean call( Integer   integer ) {
  6.  
  7. return   integer >20;
  8.  
  9. }
  10.  
  11. }).subscribe(new Action1 <Integer> () {
  12.  
  13. @Override
  14.  
  15. public void call( Integer   integer ) {
  16.  
  17. Log.e(TAG, "" + integer );
  18.  
  19. }
  20.  
  21. });

At this time, data sources 10, 13, and 16 do not meet the requirement of being greater than 20, so the default value 15 will be output. If we increase the data source data by a value of 22, then the default value will no longer be output, but 22 will be output.

takeFirst

The difference between this operator and the first operator is that if the original Observable does not emit any data that meets the conditions, first will throw a NoSuchElementException and directly execute onError(), while takeFist will return an empty Observable (onNext() will not be called but onCompleted will be called)

As shown in the following sample code

  1. Observable.just(10,11).filter(new Func1< Integer , Boolean>() {
  2.  
  3. @Override
  4.  
  5. public Boolean call( Integer   integer ) {
  6.  
  7. return   integer >20;
  8.  
  9. }
  10.  
  11. }). first ().subscribe(new Subscriber<Object>() {
  12.  
  13.   
  14.  
  15. @Override
  16.  
  17. public void onCompleted() {
  18.  
  19. Log.e(TAG, "onCompleted: " );
  20.  
  21. }
  22.  
  23.   
  24.  
  25. @Override
  26.  
  27. public void onError(Throwable e) {
  28.  
  29. Log.e(TAG, "onError: " +e.toString());
  30.  
  31. }
  32.  
  33.   
  34.  
  35. @Override
  36.  
  37. public void onNext(Object o) {
  38.  
  39. Log.e(TAG, "onNext: " +o.toString());
  40.  
  41. }
  42.  
  43. });

The output information after execution is as follows

  1. onError: java.util.NoSuchElementException: Sequence   contains   no elements

If you use takeFirst at this time

  1. Observable.just(10,11).takeFirst(new Func1< Integer , Boolean>() {
  2.  
  3. @Override
  4.  
  5. public Boolean call( Integer   integer ) {
  6.  
  7. Log.e(TAG, "call: takeFirst" );
  8.  
  9. return   integer >30;
  10.  
  11. }
  12.  
  13. }).subscribe(new Subscriber<Object>() {
  14.  
  15.   
  16.  
  17. @Override
  18.  
  19. public void onCompleted() {
  20.  
  21. Log.e(TAG, "onCompleted: " );
  22.  
  23. }
  24.  
  25.   
  26.  
  27. @Override
  28.  
  29. public void onError(Throwable e) {
  30.  
  31. Log.e(TAG, "onError: " +e.toString());
  32.  
  33. }
  34.  
  35.   
  36.  
  37. @Override
  38.  
  39. public void onNext(Object o) {
  40.  
  41. Log.e(TAG, "onNext: " +o.toString());
  42.  
  43. }
  44.  
  45. });

It is found that no exception occurs at this time, but onCompleted() is executed.

single

If the original Observable does not emit data exactly once before completion, it will throw a NoSuchElementException. In plain language, it can be understood that if the data sent is one item, the value of this item is output. If there are multiple data, an exception is thrown and the onError() method is executed.

The following code

  1. Observable.just(10, 11, 12, 13).single().subscribe(new Subscriber<Integer> ( ) {
  2.  
  3. @Override
  4.  
  5. public void onCompleted() {
  6.  
  7. Log.e(TAG, "onCompleted" );
  8.  
  9. }
  10.  
  11.   
  12.  
  13. @Override
  14.  
  15. public void onError(Throwable e) {
  16.  
  17. Log.e(TAG, "onError" +e.toString());
  18.  
  19. }
  20.  
  21.   
  22.  
  23. @Override
  24.  
  25. public void onNext( Integer   integer ) {
  26.  
  27. Log.e(TAG, integer );
  28.  
  29. }
  30.  
  31. });

Output information

  1. onError: java.util.NoSuchElementException: Sequence   contains   no elements

If you make a simple change to the above code

  1. Observable.just(10, 11, 12, 13).filter(new Func1< Integer , Boolean>() {
  2.  
  3. @Override
  4.  
  5. public Boolean call( Integer   integer ) {
  6.  
  7. return   integer > 12;
  8.  
  9. }
  10.  
  11. }).subscribe(new Subscriber <Integer> () {
  12.  
  13. @Override
  14.  
  15. public void onCompleted() {
  16.  
  17. Log.e(TAG, "onCompleted" );
  18.  
  19. }
  20.  
  21.   
  22.  
  23. @Override
  24.  
  25. public void onError(Throwable e) {
  26.  
  27. Log.e(TAG, "onError" +e.toString());
  28.  
  29. }
  30.  
  31.   
  32.  
  33. @Override
  34.  
  35. public void onNext( Integer   integer ) {
  36.  
  37. Log.e(TAG, integer );
  38.  
  39. }
  40.  
  41. });

At this time, the data 13 will be output, because there is only one data after passing the filter. single also has two variants: singleOrDefault(T) and singleOrDefault(T,Func1). You can test the difference with your own code.

Last

This operator has the opposite meaning of first. It is used when we are only interested in the last data emitted by Observable or the last data that meets a certain condition.

Sample Code

  1. Observable.just(10, 11, 12, 13) .last ().subscribe(new Action1<Integer> ( ) {
  2.  
  3. @Override
  4.  
  5. public void call( Integer   integer ) {
  6.  
  7. Log.e(TAG, "call: " + integer );
  8.  
  9. }
  10.  
  11. });

After execution, the output is 13. It has an overloaded method that can specify conditions and obtain the last data that meets the conditions. Modify the above code as follows

  1. Observable.just(10, 11, 12, 13). last (new Func1< Integer , Boolean>() {
  2.  
  3. @Override
  4.  
  5. public Boolean call( Integer   integer ) {
  6.  
  7. return   integer < 12;
  8.  
  9. }
  10.  
  11. }).subscribe(new Action1 <Integer> () {
  12.  
  13. @Override
  14.  
  15. public void call( Integer   integer ) {
  16.  
  17. Log.e(TAG, "call: " + integer );
  18.  
  19. }
  20.  
  21. });

At this time, the final output data is 11. This operator has several variants like first, such as lastOrDefault and TakeLast. You can test the specific effect yourself.

Skip

This operator skips the first few items of data and then emits the data.

  1. Observable.range(1, 10).skip(6).subscribe(new Action1<Integer> ( ) {
  2.  
  3. @Override
  4.  
  5. public void call( Integer   integer ) {
  6.  
  7. Log.e(TAG, "call: " + integer );
  8.  
  9. }
  10.  
  11. });

Output log information

  1. call: 7
  2.  
  3. call: 8
  4.  
  5. call: 9
  6.  
  7. call: 10

There are two overloaded methods for skip.skip(long time, TimeUnit unit) is executed on the computation scheduler by default. If you want to update the UI, you need to specify it as AndroidSchedulers.mainThread() through the observeOn method. Of course, there is also an overloaded method skip(long time, TimeUnit unit, Scheduler scheduler) to specify the scheduler. One thing to note is that the first parameter of these two overloaded methods is not the number of data to be skipped, but the time.

  1. Observable.interval(500, TimeUnit.MILLISECONDS)
  2.  
  3. .skip(2, TimeUnit.SECONDS)
  4.  
  5. .observeOn(AndroidSchedulers.mainThread())
  6.  
  7. .subscribe(new Subscriber<Long>() {
  8.  
  9. @Override
  10.  
  11. public void onCompleted() {
  12.  
  13.   
  14.  
  15. }
  16.  
  17.   
  18.  
  19. @Override
  20.  
  21. public void onError(Throwable e) {
  22.  
  23.   
  24.  
  25. }
  26.  
  27.   
  28.  
  29. @Override
  30.  
  31. public void onNext(Long aLong) {
  32.  
  33. tv.append( "\n" + aLong);
  34.  
  35. if (aLong > 10) {
  36.  
  37. this.unsubscribe();
  38.  
  39. }
  40.  
  41. }
  42.  
  43. });

As shown in the above code, interval generates a data every 500 milliseconds, skip is set to 2 seconds, and the subscription is unsubscribed when the data is greater than 10.

skipLast

Just the opposite of skip, ignoring the n data items generated by ***

  1. Observable.range(1, 10).skipLast(6).subscribe(new Action1<Integer> ( ) {
  2.  
  3. @Override
  4.  
  5. public void call( Integer   integer ) {
  6.  
  7. Log.e(TAG, "call: " + integer );
  8.  
  9. }
  10.  
  11. });

Output log information

  1. call: 1
  2.  
  3. call: 2
  4.  
  5. call: 3
  6.  
  7. call: 4

Continue

<<:  Experienced driver talks about racing technology: Android 7.0 adaptation experience

>>:  RxJava Operator Series 3 (Part 2)

Recommend

Global tablet shipments expected to fall 31% in first quarter of this year

Global tablet shipments are expected to decline i...

How to hide your hot update bundle files?

[[379259]] This article is reprinted from the WeC...

up to date! Data rankings of 60 information flow advertising platforms!

Today I bring you the latest traffic rankings of ...

Event budget and execution promotion for event operation!

Many people who do operations will encounter a bi...

A set of live broadcast review methodology!

1. Why do we need to do live broadcast review ? A...

Are niche milks reliable? Are they really nutritious or just a waste of money?

Are niche milks reliable? Are they really nutriti...

Testin APPBase: A head-to-head battle in the collaborative office app market

Whether the collaborative office APP itself is st...

Why doesn't the MacBook Air have a Retina display?

Another Apple product launch has ended, and we st...

The latest paper in Nature: Is it important to have water in your head?

In recent years, there is a "glymphatic clea...