The purpose of this series of articles is twofold: 1. To give anyone interested in RxJava some Pointers to get started. 2. Some deeper parsing for those of you who are using RxJava but still wondering.

At the end of the text before we start, put the GitHub link and gradle code to introduce dependencies:

  • Making: github.com/ReactiveX/R… Github.com/ReactiveX/R…
  • Introducing dependencies:The compile 'IO. Reactivex: rxandroid: 1.1.0' The compile 'IO. Reactivex: rxjava: 1.1.0'

What exactly is RxJava

RxJava – a library for composing Asynchronous and event-based programs using Observable sequences for composing The Java VM “. This is RxJava, and it’s summed up very precisely. In fact, the essence of RxJava can be reduced to the word asynchronous. At its root, it is a library that implements asynchronous operations on which all other attributes are based. In one word: asynchronous

Where is good RxJava

In other words, the same is done asynchronously, why do people use it instead of existing AsyncTask/Handler/XXX /… ? A key aspect of asynchronous operations is program brevity, because asynchronous code is often both difficult to write and difficult to read in complex scheduling situations. Android created AsyncTask and Handler to make asynchronous code simpler. RxJava also benefits from brevity, but its brevity is distinguished by its ability to keep it simple * as the program logic becomes more complex. * In one word: concise

Suppose you have a need for a custom view, imageCollectorView, that displays multiple images and can arbitrarily add images using addImage(Bitmap). Now we need the program to load the PNG images in each directory in a given directory array File[] folders and display them in imageCollectorView. Note that since the process of reading images is time-consuming, it needs to be performed in the background, whereas the display of images must be performed in the UI thread. There are several common implementations, one of which I have posted here:

new Thread() {
    @Override
    public void run() {
        super.run();
        for (File folder : folders) {
            File[] files = folder.listFiles();
            for (File file : files) {
                if (file.getName().endsWith(".png")) {
                    final Bitmap bitmap = getBitmapFromFile(file);
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() { imageCollectorView.addImage(bitmap); }}); } } } } }.start();Copy the code

With RxJava, the implementation looks like this:

Observable.from(folders)
    .flatMap(new Func1<File, Observable<File>>() {
        @Override
        public Observable<File> call(File file) {
            return Observable.from(file.listFiles());
        }
    })
    .filter(new Func1<File, Boolean>() {
        @Override
        public Boolean call(File file) {
            return file.getName().endsWith(".png");
        }
    })
    .map(new Func1<File, Bitmap>() {
        @Override
        public Bitmap call(File file) {
            returngetBitmapFromFile(file); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Bitmap>() { @Override public void call(Bitmap bitmap) { imageCollectorView.addImage(bitmap); }});Copy the code

The man said, “You have a lot of code! How simple!” . I’m talking about logical brevity, not simple code. (Logical brevity is the key to fast reading and writing code, right?) . If you look at this implementation of RxJava, it is a chain call from top to bottom, with no nesting, which has the advantage of logical simplicity. This advantage becomes even more apparent when the requirements become more complex (imagine the normal approach if only the top 10 images are required? What if there were more requirements? What if, two months after you’ve implemented a bunch of requirements, you need to change a feature, and when you go back and see the indentation of the puzzle you wrote, you can be sure that you’ll understand it quickly, rather than going through the code all over again?) .

In addition, if your IDE is Android Studio, you will actually see an automatic lambdazed preview every time you open a Java file, which will give you a clearer view of the application logic

Observable.from(folders) .flatMap((Func1) (folder) -> { Observable.from(file.listFiles()) }) .filter((Func1) (file) -> {  file.getName().endsWith(".png") })
    .map((Func1) (file) -> { getBitmapFromFile(file) })
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe((Action1) (bitmap) -> { imageCollectorView.addImage(bitmap) });

Copy the code

If you’re comfortable with Retrolambda, you can just write the code in the terse form above. And if you see here and don’t know what Retrolambda is, I don’t recommend learning about it right now. Lambda is a double-edged sword that makes your code less readable while keeping it clean, so learning RxJava and Retrolambda at the same time may cause you to overlook some of the technical details of RxJava; 2. Retrolambda is an unofficial Java 6/7 compatibility scheme for Lambda expressions, and its backward compatibility and stability are not guaranteed, so using Retrolambda is risky for enterprise projects. So, unlike many RxJava promoters, I don’t recommend learning Retrolambda along with RxJava. In fact, as much as I personally admire Retrolambda, I’ve never used it.

So what’s so good about RxJava? It’s the simplicity, the simplicity that threads any complex logic into a single line.

API introduction and principle analysis

The main content of this section is to explain step by step exactly how RxJava is asynchronous and concise.

1. Concept: Extended observer mode

The asynchronous implementation of RxJava is implemented through an extended observer pattern.

1.1 Observer Model

Let’s start with a brief description of the observer pattern. You can skip this section if you’re already familiar with it.

The observer mode is oriented to the requirement that object A (observer) is highly sensitive to A certain change of object B (observed) and needs to respond at the moment when B changes. For example, in the news, the police catch a thief. The police need to catch the thief when he reaches for his hand. In this example, the policeman is the observer and the thief is the observed. The policeman needs to keep an eye on the thief’s every move to ensure that no moment is missed. The observer mode of the program is slightly different from this kind of real “observation”. The observer does not need to stare at the observed all the time (for example, A does not need to check the status of B every 2ms). Instead, the observer registers, or subscribes, to tell the observed: I need your status, and you need to let me know when it changes. A typical example of this in Android development is the OnClickListener. For OnClickListener, the View is the observed and OnClickListener is the observer, and the subscription relationship is achieved through the setOnClickListener() method. The moment the user clicks a button after subscribes, the Android Framework sends the click event to the registered OnClickListener. Adopting this passive observation mode not only saves the resource consumption of repeatedly retrieving the state, but also can get the highest feedback speed. Of course, this also benefits from the fact that we can customize the observer and observed in our own program, while the police obviously cannot ask the thief to “inform me when you commit a crime”. The OnClickListener mode looks like this:

As shown, Button holds a reference to OnClickListener through the setOnClickListener() method (this process is not drawn); Button automatically calls the onClick() method of OnClickListener when the user clicks. In addition, if the concepts in this diagram are abstracted (Button-> Observed, OnClickListener-> Observer, setOnClickListener()-> subscription, onClick()-> event), From a dedicated observer mode (for example, only listening for clicks on controls) to a general observer mode. The diagram below:

RxJava, as a tool library, uses a generic form of the Observer pattern.

1.2 Observer mode for RxJava

RxJava has four basic concepts: Observable, Observer, Subscribe, and event. Observables and observers subscribe through the subscribe() method, which allows an Observable to notify the Observer of events when needed.

Unlike the traditional observer mode, RxJava’s event callback method defines two special events, onCompleted() and onError(), in addition to the normal onNext() event (equivalent to onClick()/onEvent()).

  • onCompleted(): The event queue ends. RxJava not only treats each event individually, but also treats them as a queue.RxJavaRule, when there will be no newonNext()When emitted, it needs to be firedonCompleted()Method as a flag.
  • onError(): The event queue is abnormal. When an exception occurs during event processing,onError()Is emitted, and the queue terminates automatically. No more events are allowed to be emitted.
  • In a correctly running sequence of events,onCompleted()andonError()There is one and only one, and it is the last one in the sequence of events. It’s important to note that,onCompleted()andonError()They are also mutually exclusive, meaning that if one is called in the queue, the other should not be called.

The observer mode for RxJava looks like this: