In-depth explanation of RxJava (1: Basics)

RxJava is becoming more and more popular among Android developers. The only problem is that it's not easy to get started, especially since most people are using imperative programming languages ​​before. But once you figure it out, you'll see how awesome RxJava is.
This is just to help you understand RxJava. There are four articles in the whole series. I hope you can understand the thinking behind RxJava after reading these four articles, and like RxJava.

The two core things of basic

RxJava are Observables (observed, event source) and Subscribers (observer). Observables emit a series of events, and Subscribers process these events. The events here can be anything you're interested in (touch events, data returned by a web interface call...)

An Observable can emit zero or more events until it ends or an error occurs. Each time an event is emitted, its Subscriber's onNext method is called, and finally Subscriber.onNext() or Subscriber.onError() is called to end.


Rxjava looks like the observer pattern in the design pattern, but there is one obvious difference, that is, if an Observer does not have any Subscriber, then the Observable will not emit any events.

Hello World

Creating an Observable object is very simple, just call Observable.create directly
Observable<String> myObservable = Observable.create(  
    new Observable.OnSubscribe<String>() {  
        @Override  
        public void call(Subscriber<? super String> sub) {  
            sub.onNext("Hello, world!");  
            sub.onCompleted();  
        }  
    }  
);

The Observable object defined here just emits a Hello World string, and then it's over. Next we create a Subscriber to process the string emitted by the Observable object.
Subscriber<String> mySubscriber = new Subscriber<String>() {  
    @Override  
    public void onNext(String s) { System.out.println(s); }  
  
    @Override  
    public void onCompleted() { }  
  
    @Override  
    public void onError(Throwable e) { }  
};

Here subscriber just prints the string emitted by the observable. Through the subscribe function, the myObservable object we defined can be associated with the mySubscriber object, thus completing the subscriber's subscription to the observable.
myObservable.subscribe(mySubscriber);

Once mySubscriber subscribes to myObservable, myObservable calls the onNext and onComplete methods of the mySubscriber object, and mySubscriber prints Hello World!
More concise

code Do you think it's too verbose to write so much code just to print a hello world? I mainly use this verbose way of writing here to show the principle behind RxJava. RxJava actually provides many convenient functions to help us reduce code.

Let's first look at how to simplify the creation of Observable objects. RxJava has many built-in functions that simplify the creation of Observable objects. For example, Observable.just is used to create an Observable object that ends after only one event is emitted. The above code for creating an Observable object can be simplified into one line
Observable<String> myObservable = Observable.just("Hello, world!");

Next, let's see how to simplify Subscriber. In the above example, we don't actually care about OnComplete and OnError. We only need to do some processing in onNext, and then we can use the Action1 class.
Action1<String> onNextAction = new Action1<String>() {  
    @Override  
    public void call(String s) {  
        System.out.println(s);  
    }  
};

The subscribe method has an overloaded version that accepts three Action1 type parameters, corresponding to OnNext, OnComplete, and OnError functions respectively.
myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction);

Here we don't care about onError and onComplete, so we only need the first parameter
myObservable.subscribe(onNextAction);  
// Outputs "Hello, world!"

The above code can finally be written like this
Observable.just("Hello, world!")  
    .subscribe(new Action1<String>() {  
        @Override  
        public void call(String s) {  
              System.out.println(s);  
        }  
    });

Using java8's lambda can make the code more concise
Observable.just("Hello, world!")  
    .subscribe(s -> System.out.println(s));

In Android development, it is strongly recommended to use the gradle plugin retrolambda, so that you can use lambda in your code.

Transform

Let's do something more interesting!
For example, if I want to add my signature to hello world, you may think of modifying the Observable object:
Observable.just("Hello, world! -Dan")  
    .subscribe(s -> System.out.println(s));

If you can mutate the Observable, that's certainly fine, but what if you can't mutate the Observable? For example, the Observable object is provided by a third-party library? For example, my Observable object is subscribed by multiple Subscribers, but I only want to modify one subscriber?
So what about modifying events in Subscriber? For example the following code:
Observable.just("Hello, world!")  
    .subscribe(s -> System.out.println(s + " -Dan"));

This way is still unsatisfactory, because I want my Subscribers to be as lightweight as possible, because I may run subscribers in the mainThread. In addition, according to the concept of reactive functional programming, what Subscribers should do is "respond", responding to the events emitted by the Observable, rather than modifying them. Wouldn't it be cool if I could transform "Hello World!" in some intermediate step?

Operators

The operator is to solve the problem of transforming the Observable object. The operator is used to modify the events emitted by the Observable between the Observable and the final Subscriber. RxJava provides many useful operators.
The map operator, for example, is used to convert one event into another.
Observable.just("Hello, world!")  
  .map(new Func1<String, String>() {  
      @Override  
      public String call(String s) {  
          return s + " -Dan";  
      }  
  })  
  .subscribe(s -> System.out.println(s));

Using lambda can be simplified to
Observable.just("Hello, world!")  
    .map(s -> s + " -Dan")  
    .subscribe(s -> System.out.println(s));

Isn't it cool? The map() operator is used to transform Observable objects. The map operator returns an Observable object, so that chained calls can be implemented. Use the map operator multiple times on an Observable object, and finally pass the most concise data to the Subscriber object.

The map operator The more interesting thing about the advanced

map operator is that it doesn't have to return the type returned by the Observable object, you can use the map operator to return an observable object that emits a new data type.
For example, in the above example, the subscriber does not care about the returned string, but wants the hash value of the string
Observable.just("Hello, world!")  
    .map(new Func1<String, Integer>() {  
        @Override  
        public Integer call(String s) {  
            return s.hashCode();  
        }  
    })  
    .subscribe(i -> System.out.println(Integer.toString(i)));

Interesting, right? Our initial Observable returns a string, and the final Subscriber receives an Integer. Of course, using lambdas can further simplify the code:
Observable.just("Hello, world!")  
    .map(s -> s.hashCode())  
    .subscribe(i -> System.out.println(Integer.toString(i)));

As mentioned earlier, the less the Subscriber does, the better, let's add a map operator
Observable.just("Hello, world!")  
    .map(s -> s.hashCode())  
    .map(i -> Integer.toString(i))  
    .subscribe(s -> System.out.println(s));

Dissatisfied?

Do you think our example is too simple to convince you? You need to understand the following two points:

1. Observable and Subscriber can do anything
Observable can be a database query, Subscriber is used to display query results; Observable can be a click event on the screen, Subscriber is used to respond to click events; Observable can be A network request that Subscriber uses to display the result of the request.

2. Observable and Subscriber are independent of the intermediate transformation process.
Any number of maps can be added or removed between Observables and Subscribers. The entire system is highly composable, and manipulating data is a straightforward process.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=327101866&siteId=291194637