Rxjava2 tutorial 2: typical implementation of Observable and Observer responsive programming in rxjava2

Posted by chooseodie on Thu, 12 Mar 2020 09:53:22 +0100

In RxJava, function responsive programming is a process in which an Observer subscribes to an Observable object, emits data flow by creating an Observable object, processes through a series of Operators, forwards between different threads by a thread Scheduler, and finally receives and responds by the Observer
ObservableSource and Observer are the most typical combination of observers and observable objects in RxJava2. The other four groups can be regarded as improved or simplified versions of this group.

Observable

The abstract class Observable is an abstract implementation under the interface ObservableSource. We can create an Observable object to transmit data flow through Observable.

     Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("Hello World");
                emitter.onComplete();
            }
        });

Call the Observable.create method, create an observable object, send a piece of data "Hello World" through onNext, and then send a completion notification through onComplete.

Observer

Create an Observer observer to accept and respond to the data emitted by the observable object

Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {

            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.out.println("Acceptance completed");
            }
        };

Receive the data "Hello World" emitted by the observable object in the onNext method, and respond -- print to the console.

Observer subscribes to Observable

observable.subscribe(observer);

By using the subscribe method, the subscription relationship between the Observer and the Observable is established. The Observer and the Observable become a whole, and the Observer can respond to the behavior in the Observable.

Emitter/Observer

When creating an observable object through Observable.create, we can find that the specific launch action is performed by the instantiated object of the interface ObservableEmitter, and the ObservableEmitter < T > inherits from the interface Emitter < T >. See the specific code of the source interface Emitter as follows:

public interface Emitter<T> {
        //It is used to send data. It can be called multiple times and send one piece of data each time
    void onNext(@NonNull T value);
        //It is used to send exception notifications only once. If multiple calls are made, only the first one will be sent
    void onError(@NonNull Throwable error);
        //It is used to send the completion notice only once. If it is called multiple times, only the first one will be sent
    void onComplete();
}

onNext: used to send data. It can be called multiple times, sending one piece of data each time
onError: used to send exception notification once only. If multiple calls are made, only the first one will be sent
onComplete: used to send the completion notification once only. If it is called multiple times, only the first one will be sent

onError and onComplete are mutually exclusive. Two methods can only be called one, not both

When sending data, if there is an exception, you can call onError to send an exception notification or not, because its method subscription will throw an exception,

If all data is normal after sending, you can call onComplete to send a completion notice

The three methods in the interface Observer (onNext,onError,onComplete) correspond to the three methods in the twitter, and respond to the data or notifications sent by the corresponding methods in the twitter.

Step simplification

Removing the intermediate variable can simplify the previous code to the following form:

    public void demo2() {
        Observable
                .create(new ObservableOnSubscribe<String>() {
                    @Override
                    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                        emitter.onNext("Hello World");
                        emitter.onComplete();
                    }
                })
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(String s) {
                        System.out.println(s);
                    }

                    @Override
                    public void onError(Throwable e) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onComplete() {
                        System.out.println("Acceptance completed");
                    }
                });
    }

By applying the powerful operators in Rxjava, the code can be simplified into the following forms:

    public void demo3() {
        Observable.just("Hello World")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
    }

The λ expression can be further simplified

    public void demo3_1() {
        Observable.just("Hello World").subscribe(System.out::println);
    }

Among them, the just operator can be used to send single data, numbers, strings, arrays, objects, and collections can be sent as single data.
Consumer can be seen as a product of the simplification of Observer function - consumer. In the above example, consumer only receives data from observable objects through its function accept, and does not receive abnormal information or completion information.
If you want to receive exception information or completion information, you can use the following code:

    public void demo4() {
        Observable.just("Hello World")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        throwable.printStackTrace();
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        System.out.println("Acceptance completed");
                    }
                });
    }

The second parameter, Consumer, specifies that the generic < throwable > receives exception information through the function accept.
The third parameter, Action, is also the product of the Observer's simplification of function - Action. It receives the completion information through the function run and makes response actions.

Send data series

Observable can send single data or data sequence
Send data series through the most basic method:

public void demo5(final List<String> list) {
        Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                try {
                    for (String str : list) {
                        emitter.onNext(str);
                    }
                    emitter.onComplete();
                } catch (Exception e) {
                    emitter.onError(e);
                }
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(String s) {
                System.out.println(s);
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.out.println("Acceptance completed");
            }
        });
    }

In the subscribe method, traverse the String element in the collection list and send it one by one via twitter.onnext (STR); after sending, send the completion notification via Twitter. Oncomplete(); if there is an exception in the sending process, send the exception information via twitter.onerror (E).
The Observer receives each message sent by the emitter through onNext and prints it to the console (the emitter sends it several times, the Observer receives it several times), receives the exception message through onError(Throwable e), and receives the completion message through onComplete().
It can also be simplified by operators, as follows:;

    public void demo6(final List<String> list) {
        Observable
                .fromIterable(list)
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
    }

Further simplify it with λ expression

    public void demo6_1(final List<String> list) {
        Observable.fromIterable(list).subscribe(System.out::println);
    }

The from iterative operator can be used to send elements of an iterative object one by one

Disposable

In the previous example, you can see that there is another method in the Observer interface

public void onSubscribe(Disposable d) {
}

After the Observer observer and Observable object establish a subscription relationship, call back this method, and pass a parameter of Disposable type to control the subscription between the Observer and Observable through Disposable.
No matter how Observer subscribes to Observable object Observable, a Disposable will be generated, as follows:

public void demo7(final List<String> list) {
        Disposable disposable1 = Observable.just("Hello World")
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
        Disposable disposable2 = Observable
                .fromIterable(list)
                .subscribe(new Consumer<String>() {
                    @Override
                    public void accept(@NonNull String s) throws Exception {
                        System.out.println(s);
                    }
                });
    }

Check the source code of the Disposable interface as follows:

public interface Disposable {
        void dispose();
        boolean isDisposed();
}

The isDisposed() method is used to determine whether the current subscription is invalid, and the dispose() method is used to cancel the current subscription.
Only when a subscription relationship is established between Observer and Observable object, and the subscription relationship is valid, can Observer respond to Observable. If the subscription relationship of the Observer is cancelled during the process of responding to the Observable, the Observer cannot respond to the behavior of the Observable after canceling the subscription relationship.
Run the following code to unsubscribe when the Observable receives the 5th data.

public void demo8() {
        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                for (int i = 0; i < 10; i++) {
                    System.out.println("Send out" + i);
                    emitter.onNext(i);
                }
                emitter.onComplete();
            }
        }).subscribe(new Observer<Integer>() {
            private Disposable disposable;

            @Override
            public void onSubscribe(Disposable d) {
                disposable = d;
            }

            @Override
            public void onNext(Integer integer) {
                System.out.println("Receive" + integer);
                if (integer > 4) disposable.dispose();
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onComplete() {
                System.out.println("Data acceptance completed");
            }
        });
    }

The console logs are as follows:

 I/System.out: send 0
 I/System.out: receive 0
 I/System.out: send 1
 I/System.out: receive 1
 I/System.out: send 2
 I/System.out: receive 2
 I/System.out: send 3
 I/System.out: receive 3
 I/System.out: send 4
 I/System.out: receive 4
 I/System.out: send 5
 I/System.out: receive 5
 I/System.out: send 6
 I/System.out: send 7
 I/System.out: send 8
 I/System.out: send 9

It can be found that before canceling the subscription relationship, the Observable sends a piece of data, and the Observable receives one. However, after canceling the subscription relationship, the Observable will no longer receive the data sent by the Observable.

84 original articles published, 67 praised, 80000 visitors+
Private letter follow

Topics: Programming