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.