Rxjava2 introduction and detailed examples

Posted by bearqst on Sat, 04 Jan 2020 08:10:41 +0100

Preface

Now we can see that more and more developers are using RX related technologies to develop apps, Java backend and other fields. In open source communities and Internet companies, Rx, responsive programming, and functional are popular. Therefore, the author will write a series of articles on Rxjava2 in combination with his own learning and actual use, so as to learn and use the convenience brought by Rxjava together.

In addition to my work, I will combine the definition and introduction of Rxjava with the official Wiki of ReactiveX, sort out the relevant basic knowledge, basic operation and API of common parts, and add personal understanding and examples of relevant operation.

Related reference links:

Rxjava2 series article directory:

Instance code:

RX introduction

History of ReactiveX

Reactive x is the abbreviation of Reactive Extensions, which is generally abbreviated as Rx. It was originally an extension of LINQ. It was developed by a team led by Erik Meijer, an architect of Microsoft. It was open-source in November 2012. Rx is a programming model. The goal is to provide a consistent programming interface to help developers deal with asynchronous data flow more easily. The RX library supports. NET, JavaScript and C + +. RX has become more and more popular in recent years It's popular. Now it supports almost all popular programming languages. Most of the language libraries of Rx are maintained by ReactiveX. The popular ones are RxJava/RxJS/Rx.NET, and the community website is reactivex.io.

What is ReactiveX

The definition given by Microsoft is that Rx is a function library, which allows developers to use observable sequences and LINQ style query operators to write asynchronous and event-based programs. With Rx, developers can use Observables to represent asynchronous data flows, LINQ operators to query asynchronous data flows, and schedulers to parameterize the concurrent processing of asynchronous data flows. RX can be defined as RX = observer vables + LINQ + Schedulers.

The definition of ReactiveX.io is that Rx is a programming interface for asynchronous programming using observable data streams. ReactiveX combines the essence of observer mode, iterator mode and functional programming.

What exactly is RxJava

RxJava's self introduction on GitHub homepage is "a library for compositing asynchronous and event based programs using observable sequences for the Java VM". This is RxJava, which is very precise.

However, for beginners, this is more subtle. Because it is a summary, and beginners need an introduction or understanding. In fact, the essence of RxJava can be summed up as the concept of asynchrony. In essence, it is a library for asynchronous operations. The asynchronous implementation of RxJava is implemented through an extended observer pattern.

RxJava benefits

It's also asynchronous. Why use it instead of the existing Thread, ThreadPoolExecutor, Android's AsyncTask / Handler /? In fact, it is simple and easy to use!

The key point of asynchronous operation is the simplicity of the program, because in the case of complex scheduling process, asynchronous code is often difficult to write and understand. Just like the AsyncTask and Handler created by Android, they are all designed to make asynchronous code more concise. RxJava also has the advantage of simplicity, but the difference of its simplicity is that it can still keep simplicity as the program logic becomes more and more complex.

Noun definition

  • Reactive literal translation is reactive and active, which is generally translated into reactive and reactive according to the context.
  • Iteratable can iterate over objects, supporting traversal in the form of iterators, a concept that exists in many languages.
  • Observable observable object, defined as a more powerful Iterable in Rx, is the observed object in observer mode. Once the data is generated or changed, the observer or subscriber will be notified in some way.
  • The Observer object of the Observer listens to the data transmitted by the Observable and responds. The Subscriber is a special implementation of the Observer object.
  • The meaning of emit is that Observable sends a notice to the Observer when the data is generated or changed, and calls the corresponding method of the Observer. In this article, all of them are translated into transmit.
  • In Rx, items refer to data items transmitted by Observable. In the article, all items are translated into data items.

Rx mode

Using observer mode

  • Create: Rx can easily create event flow and data flow
  • Combination: Rx uses query operators to combine and transform data flow
  • Listening: Rx can subscribe to any observable data stream and perform operations

Simplified code

  • Functional style: use input and output functions without side effects for observable data flow to avoid complicated states in the program
  • Simplify code: the operators of Rx can usually simplify complex problems into a few lines of code
  • Asynchronous error handling: traditional try/catch can't handle asynchronous computing. Rx provides an appropriate error handling mechanism
  • Easy to use Concurrency: Rx's Observables and Schedulers let developers get rid of the underlying thread synchronization and various Concurrency problem

Advantages of using Observable

Rx extends the observer pattern to support data and event sequences, adding operators that allow you to declaratively combine these sequences without paying attention to the underlying implementation: threads, synchronization, thread safety, concurrent data structures, and non blocking IO.

Observable fills this gap by using the best way to access asynchronous data sequences.

type Single data Multiple data
synchronization T getData() Iterable<T> getData
asynchronous Future<T> getData() Observable<T> getData()

Rx's Observable model allows you to operate asynchronous event flows just as you would with aggregate data, using a variety of Simple, composable operation.

1. Observable can be combined

For single-layer asynchronous operations, the processing of Future objects in Java is very simple and effective, but when it comes to nesting, they start to become extremely cumbersome and complex. It's very difficult to use Future to combine conditional asynchronous execution processes (considering various potential problems at runtime, or even impossible). Of course, it can be achieved if you want to achieve it, but it's very difficult. Maybe you can use Future.get(), but in this way, the advantages of asynchronous execution are completely lost. On the other hand, Rx's bserveable was originally designed to combine asynchronous data streams.

2. More flexible observable

Rx's observable supports not only processing individual scalar values (as Future can do), but also data sequences, or even infinite data flows. Observable is an abstract concept, applicable to any scenario. Observable has all the grace and flexibility of its close relative Iterable.

Observable is asynchronous two-way push, and iterative is synchronous one-way pull

Event Iterable(pull) Observable(push)
get data T next() onNext(T)
exception handling throws Exception onError(Exception)
Mission accomplished !hasNext() onCompleted

3. Observable

Rx has no special preference for concurrency or asynchrony. Observable can be implemented in any way, such as thread pool, event loop, non blocking IO, Actor mode, whatever way you are good at or prefer to meet your needs. No matter how you choose to implement it, whether the underlying implementation is blocking or non blocking, the client code treats all interactions with observable as asynchronous.

Rx usage dependency:

The following versions are used by the author (can be selected according to the actual situation):

  1. Using Gradle dependency: implementation "io.reactivex.rxjava2:rxjava:2.2.12"
  2. Use Maven dependency or Jar package to download: Rxjava 2.2.12
  3. Other versions and related downloads: Maven

The foundation of Rxjava

1. Observable

1.1 observer mode

Basic concepts: Observable, Observer, subscribe, event. The subscription relationship between the Observable and the Observer is realized through the subscribe() method, so that the Observable can send an event to inform the Observer when necessary (the Observer observes the notification event of the observed).

In RxJava, an object that implements the Observer interface can subscribe to an instance of the Observable class. Subscribers respond to any data or sequence of data that is emitted by Observable. This mode simplifies concurrent operations, because it does not need to block waiting for the Observable to launch data, but creates a standby Observer sentry, who responds to the Observable's notification at some time in the future.

The event callback methods of RxJava: onSubscribe(), onNext(), onCompleted(), and onError().

  • onSubscribe(): triggered when the observed is subscribed by the observer.
  • onNext(): this method is used to inform the observer of data transformation when the observed sends data.
  • onCompleted(): end of event queue. RxJava not only processes each event individually, but also treats them as a queue. RxJava specifies that when no new onNext() is issued, the onCompleted() method needs to be triggered as a flag.
  • onError(): event queue exception. When an exception occurs during event processing, onError() will be triggered, and the queue will be terminated automatically. No more events are allowed.

Note: in a properly running event sequence, onCompleted() and onError() have one and only one, and are the last in the event sequence. It should be noted that onCompleted () and onError () two are mutually exclusive, that is, one of them is invoked in the queue, so we should not call another one.

1.2 Consumer and Action

These two words mean consumers (which can be understood as consuming the events emitted by the observed) and behaviors (which can be understood as responding to the observed behaviors). For the four callback methods in the Observer, we may not be able to use them all. If we only need to use some of them, we need to use the Consumer and Action.

Simple example:

	// 1. subscribe(Observer)
	observable.subscribe(observer);
		
	System.out.println("---------------------------------------------");
	// 2. subscribe(Consumer onNext)
	observable.subscribe(nextConsumer);
	
	System.out.println("---------------------------------------------");
	// 3. subscribe(Consumer onNext, Consumer onError)
	observable.subscribe(nextConsumer, errorConsumer);
		
	System.out.println("---------------------------------------------");
	// 4. subscribe(Consumer onNext, Consumer onError, Action onCompleted)
	observable.subscribe(nextConsumer, errorConsumer, completedAction);
		
	System.out.println("---------------------------------------------");
	// 5. subscribe(Consumer onNext, Consumer onError, Action onCompleted, Consumer onSubscribe)
	observable.subscribe(nextConsumer, errorConsumer, completedAction, onSubscribeComsumer);

1.3 classification of observable

In RxJava, Observable can be divided into Hot and Cold.

  • Hot Observable: the event will always occur whether or not the observer subscribes. When there are multiple subscribers, Hot Observable can share information with multiple subscribers.
  • Cold Observable: only when an observer subscribes, can the data flow be sent, and the relationship with the observer is one-to-one. When there are multiple different subscribers, the messages are re sent completely, that is to say, for subscribers, their events are independent of each other.

Javadoc: Observable

2. Flowable

In Rxjava2.x, there is such an Observable as Flowable. What's the difference between Flowable and Observable? In Rxjava2, the Observable no longer supports backpressure, while the new Flowable supports backpressure. What is backpressure? It's the phenomenon that the speed of upstream sending events is faster than that of downstream processing events in asynchronous scenarios.

Tip: there will be a separate chapter later in this series on how to use backpressure.
Javadoc: Flowable

3. Single

Single is similar to Observable, except that it always emits only one value, or an error notification, rather than a series of values.

Therefore, unlike Observable, you need three methods, onnext, onerror, oncompleted. You only need two methods to subscribe to Single:

  • onSuccess: Single sends a single value to this method
  • onError: if the required value cannot be emitted, Single will emit a Throwable object to this method

Single will only call one of these two methods, and only once. After any method is called, the subscription relationship is terminated.

Example code:

	// Single: only send the onSuccess or onError notification once, and the first time after sending the data will not be processed
	Single.create(new SingleOnSubscribe<String>() {
	
			@Override
			public void subscribe(SingleEmitter<String> emitter) throws Exception {
				emitter.onSuccess("Success");			// Send success notification
				emitter.onSuccess("Success2");		// Only one notification can be sent, and it will not be processed later
			}
	}).subscribe(new BiConsumer<String, Throwable>() {
	
			@Override
			public void accept(String t1, Throwable t2) throws Exception {
				System.out.println("--> accept: t1 = " + t1 + ",  t2 = " + t2);
			}
	});

Output:

--> accept: t1 = Success,  t2 = null

Tip: Single can be converted to Observable, Flowable, Completable and may through toXXX method.
Javadoc: Single

4. Completable

After the Completable is created, no data will be emitted, only the onComplete and onError events, and there are no Observable operators, such as map and flatMap. Usually used in conjunction with the andThen operator.

Example code:

	// 1. Completed: only complete or error events are sent, and no data is sent
	Completable.fromAction(new Action() {

		@Override
		public void run() throws Exception {
			System.out.println("Hello World! This is Completable.");
		}
	}).subscribe(new CompletableObserver() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--> onSubscribe");
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError");
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete");
		}
	});

	System.out.println("----------------------------------------------");
	// 2. It is used in combination with andThen. When the completed is completed, the task in andThen is executed
	Completable.create(new CompletableOnSubscribe() {

		@Override
		public void subscribe(CompletableEmitter emitter) throws Exception {
			Thread.sleep(1000);
			System.out.println("--> completed");
			emitter.onComplete();
		}
	}).andThen(Observable.range(1, 5)).subscribe(new Consumer<Integer>() {

		@Override
		public void accept(Integer t) throws Exception {
			System.out.println("--> accept: " + t);
		}
	});

Output:

--> onSubscribe
Hello World! This is Completable.
--> onComplete
----------------------------------------------
--> completed
--> accept: 1
--> accept: 2
--> accept: 3
--> accept: 4
--> accept: 5

Tip: the Completable can be converted to Observable, Flowable, Single and Maybe through the toXXX method.
Javadoc: Completable

5. Maybe

Maybe is a new type after Rxjava 2.x, which can only transmit 0 or 1 item of data. Even if there are multiple data in the future, the latter data will not be processed. It can be seen as a combination of Single and Completable.

Example code:

	// Maybe only sends 0 or 1 data, and subsequent data will be ignored
	Maybe.create(new MaybeOnSubscribe<String>() {

		@Override
		public void subscribe(MaybeEmitter<String> emitter) throws Exception {
			// If it is sent first, the onCompleted method of MaybeObserver will be called. If there is any data sending or calling onError, it will not be called
			// emitter.onComplete();
			emitter.onSuccess("Hello"); // If the first data is sent, subsequent data will not be processed
			emitter.onSuccess("World");
		}
	}).subscribe(new MaybeObserver<String>() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--> onSubscribe");
		}

		@Override
		public void onSuccess(String t) {
			System.out.println("--> onSuccess: " + t);
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError: " + e);
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete");
		}
	});

Output:

--> onSubscribe
--> onSuccess: Hello

Tip: Maybe can be converted to Observable, Flowable, Single and Completable through toXXX method.
Javadoc: Maybe

6. Subject

Subject can be regarded as a bridge or agent. In RxJava implementation, it plays the role of both Observer and Observable. Because it is an Observer, it can subscribe to one or more observables, and because it is an Observable, it can forward the data it receives or send new data.

It can be either the data source Observer or the data subscriber Observer. This can be learned through the source code.

public abstract class Subject<T> extends Observable<T> implements Observer<T> {
    ...
}

In fact, the Subject is still Observable, but because it implements the Observer interface, it can transmit and terminate the transmitted data through the methods of onNext, onComplete and onError.

Note: do not use just(T), from(T), create(T) to use Subject, because it will be converted to observable.

In Rxjava, the official provides us with several subjects:

  • AsyncSubject (release only the last data received)
  • BehaviorSubject (release the last data before subscription and all data received after subscription)
  • PublishSubject (data received after releasing the subscription)
  • ReplaySubject (release all data received)
  • UnicastSubject (only once subscribed subjects are supported)
  • Serialized (serialized)
  • TestSubject (replaced by TestScheduler and TestObserver in 2.x)

6.1 AsyncSubject

AsyncSubject only releases the last data before onComplete() (subject.onComplete() must be called to send data, otherwise the observer will not receive any data).

The final result data of data business logic can be obtained.

Note: if terminated due to an Error, no data will be released to the subsequent Observer, but an exception notification will be passed to the Observer.

Instance code:

	// Note: do not use just(T), from(T), create(T) to use Subject, because it will convert Subject to observable
	// Whether AsyncSubject is Completed or not at the time of subscription, you can receive the callback of the last value
	AsyncSubject<String> asyncSubject = AsyncSubject.create();
	asyncSubject.onNext("emitter 1");
	asyncSubject.onNext("emitter 2");
	asyncSubject.onNext("emitter 3");
	asyncSubject.onNext("emitter 4");
	asyncSubject.onNext("emitter 5"); // This data will be sent after subscription
	// asyncSubject.onNext(1/0 + ""); / / when an error occurs, no data will be transmitted, only error notification will be sent
	asyncSubject.onComplete();

	// Only the last data will be received after subscription
	asyncSubject.subscribe(new Observer<String>() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--> onSubscribe");
		}

		@Override
		public void onNext(String t) {
			System.out.println("--> onNext = " + t);
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError = " + e);
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete");
		}
	});

Output:

--> onSubscribe
--> onNext = emitter 5
--> onComplete

Javadoc: AsyncSubject

6.2 BehaviorSubject

When the observer subscribes to BehaviorSubject, it starts to transmit the last transmitted data before the original Observable subscribes (if no data has been received at this time, it will transmit a default value), and then continue to transmit any other data from the original Observable.

You can cache the last data issued before the subscription and all data sent after the subscription.

Note: if terminated due to an Error, no data will be released to the subsequent Observer, but an exception notification will be passed to the Observer.

Instance code:

	// Create BehaviorSubject without default
	BehaviorSubject<Integer> subject = BehaviorSubject.create();
	// Create BehaviorSubject with default value
	BehaviorSubject<Integer> subjectDefault = BehaviorSubject.createDefault(-1);
	
	// Observer object
	Observer<Integer> observer = new Observer<Integer>() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--------------------------------");	
			System.out.println("--> onSubscribe");
		}

		@Override
		public void onNext(Integer t) {
			System.out.println("--> onNext: " + t);
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError: " + e);
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete");
		}
	};
	
	// 1. Send default value when no data is sent
	//	subjectDefault.subscribe(observer);
	
	// 2. At this time, all subscribed data will be sent: 1, 2, 3, 4, error
	//	subject.subscribe(observer);
	subject.onNext(1);
	subject.onNext(2);
	subject.onNext(3);
	
	// 3. At this time, the data before subscription and the data after subscription will be transmitted normally: 3, 4, error
	//	subject.subscribe(observer);
	subject.onNext(4);
	subject.onError(new NullPointerException());
	
	// 4. No subsequent data will be sent at this time, only Error notification will be sent
	//	subject.subscribe(observer);
	subject.onNext(5);
	subject.onComplete();
	
	// 5. There is no data transmission at this time. If an error exists, an error will be sent
	subject.subscribe(observer);

Output:

--------------------------------
--> onSubscribe
--> onNext: -1
--------------------------------
--> onSubscribe
--> onNext: 1
--> onNext: 2
--> onNext: 3
--> onNext: 4
--> onError: java.lang.NullPointerException
--------------------------------
--> onSubscribe
--> onNext: 3
--> onNext: 4
--> onError: java.lang.NullPointerException
--------------------------------
--> onSubscribe
--> onError: java.lang.NullPointerException
--------------------------------
--> onSubscribe
--> onError: java.lang.NullPointerException

Javadoc: BehaviorSubject

6.3 PublishSubject

PublishSubject will only send data from the original Observable to the observer after the point when the subscription occurs. It should be noted that PublishSubject may launch data as soon as it is created (unless you can prevent it from happening), so there is a risk that one or more data may be lost between the time when the Subject is created and the time when the observer subscribes to it. If you want to ensure that all data from the original Observable is distributed, you need to do this: Create that Observable using Create to manually introduce "cold" Observable behavior to it (start emitting data when all observers have subscribed), or use ReplaySubject instead.

If the PublishSubject has called the onComplete() method before subscribing, the observer will not receive the data.

Note: if terminated due to an Error, no data will be released to the subsequent Observer, but an exception notification will be passed to the Observer.

Instance code:

	// After the subscription is released, the normal transmitted data is received. If there is an error, no data will be transmitted
	PublishSubject<Integer> subject = PublishSubject.create();
	// Observer object
	Observer<Integer> observer = new Observer<Integer>() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--------------------------------");
			System.out.println("--> onSubscribe");
		}

		@Override
		public void onNext(Integer t) {
			System.out.println("--> onNext: " + t);
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError: " + e);
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete");
		}
	};
	
	// 1. At this time, the subscription will release the subsequent normal data: 1, 2, 3, 4, error
	// subject.subscribe(observer);
	subject.onNext(1);
	subject.onNext(2);
	
	// 2. At this time, subscribe and launch the data of subsequent normal launches: 3, 4, error
	// subject.subscribe(observer);
	subject.onNext(3);
	subject.onNext(4);
	
	// No data will be sent at this time. error will be sent directly
	subject.onError(new NullPointerException());
	subject.onNext(5);
	subject.onComplete();
	
	// 3. At this time, if there is an error in the subscription, only send the error, otherwise there is no data transmission
	subject.subscribe(observer);

Output:

--------------------------------
--> onSubscribe
--> onNext: 1
--> onNext: 2
--> onNext: 3
--> onNext: 4
--> onError: java.lang.NullPointerException
--------------------------------
--> onSubscribe
--> onNext: 3
--> onNext: 4
--> onError: java.lang.NullPointerException
--------------------------------
--> onSubscribe
--> onError: java.lang.NullPointerException

Javadoc: PublishSubject

6.4 ReplaySubject

ReplaySubject will send all data from the original Observable to the observer, no matter when they are subscribed. There are also other versions of ReplaySubject, which discard the old data (transmitted by the original Observable) when the replay cache grows to a certain size or after a period of time.

If you use ReplaySubject as an observer, be careful not to call its onNext methods (including other on series methods) from multiple threads, which may lead to simultaneous (non sequential) calls, which will violate Observable protocol and increase the uncertainty of Subject results.

ReplaySubject can also limit the number of cached data and cache time:

  • create(bufferAge): Specifies the internal cache to reduce the excessive redistribution of internal cache growth
  • createWithSize(maxAge): specify the maxAge data items that have previously been transmitted after subscription
  • createWithTime(timeout, TimeUnit, Scheduler): After accepting the subscription, accept the data items that have been launched in the specified timeout period before

Instance code:

	// 1. Accept all received data and notifications, and perform the same independent operation for every Observer
	ReplaySubject<Integer> subject = ReplaySubject.create();
	
	// 2. Specify the internal cache size. This method avoids excessive array reallocation when the internal buffer grows to accommodate the new buffer
	// ReplaySubject<Integer> subject = ReplaySubject.create(5);
	
	// 3. createWithSize(count) 
	// The Subject that specifies to keep the number of data items before subscription will emit count data before subscription and subsequent data
	// ReplaySubject<Integer> subject = ReplaySubject.createWithSize(1);
	
	// 4. createWithTime(maxAge, unit, scheduler) 
	// Specify the data within the specified maxAge period and subsequent data before reservation subscription
	// ReplaySubject<Integer> subject = ReplaySubject.createWithTime(1, TimeUnit.MILLISECONDS, Schedulers.trampoline());

	// Create an observer, which can accept all notifications of Observable
	Observer<Integer> observer = new Observer<Integer>() {

		public void onSubscribe(Disposable d) {
			System.out.println("----------------------------------");
			System.out.println("--> onSubscribe");
		}

		public void onNext(Integer t) {
			System.out.println("--> onNext = " + t);
		}

		public void onError(Throwable e) {
			System.out.println("--> onError: " + e);
		}

		public void onComplete() {
			System.out.println("--> onComplete");
		}
	};
	
	// Normal acceptance of all Observable data and notifications
	subject.subscribe(observer);
	subject.onNext(1);
	subject.onNext(2);
	subject.onNext(3);
	
	// Normal acceptance of all Observable data and notifications
	subject.subscribe(observer);
	subject.onNext(4);
	// If there is an error, an error notification will be sent, which will not affect any observer's data and notification acceptance
	// subject.onError(new NullPointerException());
	subject.onNext(5);
	subject.onComplete();
	
	// Normal acceptance of all Observable data and notifications
	subject.subscribe(observer);

Output:

----------------------------------
--> onSubscribe
--> onNext = 1
--> onNext = 2
--> onNext = 3
----------------------------------
--> onSubscribe
--> onNext = 1
--> onNext = 2
--> onNext = 3
--> onNext = 4
--> onNext = 4
--> onNext = 5
--> onNext = 5
--> onComplete
--> onComplete
----------------------------------
--> onSubscribe
--> onNext = 1
--> onNext = 2
--> onNext = 3
--> onNext = 4
--> onNext = 5
--> onComplete

Javadoc: ReplaySubject

6.5 UnicastSubject

UnicastSubject is a Subject that only supports subscription once. If multiple subscribers attempt to subscribe to the Subject, they will be Subject to IllegalStateException.

It is often used in one-time consumption or security occasions, such as network settlement, payment, etc.

Instance code:

	// To create UnicastSubject, you can only be subscribed once, and cannot be subscribed again
	UnicastSubject<Integer> subject = UnicastSubject.create();
	
	// Create an observer, which can accept all notifications of Observable
	Observer<Integer> observer = new Observer<Integer>() {

		public void onSubscribe(Disposable d) {
			System.out.println("--------------------------------");
			System.out.println("--> onSubscribe");
		}

		public void onNext(Integer t) {
			System.out.println("--> onNext = " + t);
		}

		public void onError(Throwable e) {
			System.out.println("--> onError: " + e);
		}

		public void onComplete() {
			System.out.println("--> onComplete");
		}
	};
	// After subscription, this subject can no longer be subscribed
	subject.subscribe(observer);
	
	subject.onNext(1);
	subject.onNext(2);
	subject.onNext(3);
	// There will be IllegalStateException at this time, because you can only subscribe once, and you cannot subscribe repeatedly
	subject.subscribe(observer);
	subject.onNext(4);
	subject.onNext(5);
	subject.onComplete();
	
	// At this time, there will be IllegalStateException, because it can only be subscribed once and cannot be subscribed repeatedly
	subject.subscribe(observer);

Output:

--------------------------------
--> onSubscribe
--> onNext = 1
--> onNext = 2
--> onNext = 3
--------------------------------
--> onSubscribe
--> onError: java.lang.IllegalStateException: Only a single observer allowed.
--> onNext = 4
--> onNext = 5
--> onComplete
--------------------------------
--> onSubscribe
--> onError: java.lang.IllegalStateException: Only a single observer allowed.

Javadoc: UnicastSubject

6.6 SerializedSubject

In the case of concurrency, it is not recommended to use the common Subject object. In this case, a series of uncontrollable problems will occur due to multiple calls. Instead, it is recommended to use serialized Subject. Only one thread is allowed to call methods such as onNext during concurrency. After the Subject is serialized, all other Observable and Subject methods are thread safe.

Note: in Rxjava2, SerializedSubject is a non-public (not public) type, which means that it can not be directly created and used, but its thread safety can be guaranteed by serializing the Subject object through the Subject.toSerialized() method. At the same time, it also provides serialized observer, serialized subscriber, etc. to wrap objects into serialized objects.

Instance code:

	// Create Subject
	ReplaySubject<String> subject = ReplaySubject.create();

	// Serialization through toSerialized()
	Subject<String> serialized = subject.toSerialized();

	// Subscribe
	serialized.subscribe(new Consumer<String>() {

		@Override
		public void accept(String t) throws Exception {
			System.out.println("--> accept: " + t + ", ReceiverThreadID: " + Thread.currentThread().getId());
		}
	});

	// Multithreaded execution
	for (int i = 0; i < 10; i++) {
		final int value = i + 1;
		new Thread(new Runnable() {

			@Override
			public void run() {
				serialized.onNext(value + "-SendThreadID: " + Thread.currentThread().getId());
			}
		}).start();
	}

	System.in.read();
	
	System.out.println("---------------------------------------------------------------------");

	// Create a serialized observer for serialization to ensure thread safety
	// Note: only one thread can call the onnext, oncompleted and onerror methods at the same time, not all the emit values are put on one thread and processed
	SerializedObserver<String> observer = new SerializedObserver<String>(new Observer<String>() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--> onSubscribe");
		}

		@Override
		public void onNext(String t) {
			System.out.println("--> onNext: " + t + ", ReceiverThreadID: " + Thread.currentThread().getId());
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError");
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete");
		}
	});

	// Subscribe
	subject.subscribe(observer);

	// Multithreaded execution
	for (int i = 0; i < 10; i++) {
		final int value = i + 1;
		new Thread(new Runnable() {

			@Override
			public void run() {
				subject.onNext(value + "-SendThreadID: " + Thread.currentThread().getId());
		//		if (value == 10) {
		//			subject.onComplete();
		//		}
			}
		}).start();
	}

	System.in.read();

Output:

--> accept: 1-SendThreadID: 11, ReceiverThreadID: 11
--> accept: 2-SendThreadID: 12, ReceiverThreadID: 11
--> accept: 10-SendThreadID: 20, ReceiverThreadID: 11
--> accept: 9-SendThreadID: 19, ReceiverThreadID: 11
--> accept: 8-SendThreadID: 18, ReceiverThreadID: 11
--> accept: 7-SendThreadID: 17, ReceiverThreadID: 11
--> accept: 6-SendThreadID: 16, ReceiverThreadID: 11
--> accept: 4-SendThreadID: 14, ReceiverThreadID: 11
--> accept: 5-SendThreadID: 15, ReceiverThreadID: 11
--> accept: 3-SendThreadID: 13, ReceiverThreadID: 11
---------------------------------------------------------------------
--> onSubscribe
--> onNext: 1-SendThreadID: 11, ReceiverThreadID: 11
--> onNext: 3-SendThreadID: 13, ReceiverThreadID: 11
--> onNext: 4-SendThreadID: 14, ReceiverThreadID: 11
--> onNext: 5-SendThreadID: 15, ReceiverThreadID: 11
--> onNext: 6-SendThreadID: 16, ReceiverThreadID: 16
--> onNext: 7-SendThreadID: 17, ReceiverThreadID: 16
--> onNext: 8-SendThreadID: 18, ReceiverThreadID: 16
--> onNext: 9-SendThreadID: 19, ReceiverThreadID: 16
--> onNext: 10-SendThreadID: 20, ReceiverThreadID: 16

6.7 TestSubject

In Rxjava2, TestSubject has been canceled, and TestScheduler and TestObserver are used instead. The following is mainly introduced with TestObserver as an example.

TestObserver is an observer that records events and allows assertions. It is often used in test situations. In general, you can create a TestObserver object or directly call the test() method from the Observable or Subject.

Instance code:

	// Observable
	Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {

		@Override
		public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
			emitter.onNext(1);
			emitter.onNext(2);
			emitter.onNext(3);
			emitter.onNext(100);
			emitter.onError(new NullPointerException());
			emitter.onComplete();
		}
	});

	// 1. Create TestObserver object
	TestObserver<Integer> testObserver = TestObserver.create(new Observer<Integer>() {

		@Override
		public void onSubscribe(Disposable d) {
			System.out.println("--> onSubscribe:");
		}

		@Override
		public void onNext(Integer t) {
			System.out.println("--> onNext: " + t);
		}

		@Override
		public void onError(Throwable e) {
			System.out.println("--> onError: " + e);
		}

		@Override
		public void onComplete() {
			System.out.println("--> onComplete:");
		}
	});

	observable.subscribe(testObserver);
	try {
		// Assert whether to receive subscription, but no event is sent
		testObserver.assertEmpty();
		// Assert whether to receive onComplete()
		testObserver.assertComplete();
		// Assert no data 100 sent
		testObserver.assertNever(100);
		// Assert receive data results
		testObserver.assertResult(1, 2, 3);
		// Assertion exception
		testObserver.assertError(NullPointerException.class);
		... For more information, please refer to Api
	} catch (Error e) {
		System.out.println("Error: " + e);
	}

	System.out.println("-----------------------------------------------");
	// Subject
	AsyncSubject<Object> subject = AsyncSubject.create();

	// 2. Get TestObserver object from Observable or Subject
	TestObserver<Integer> test = observable.test();
	TestObserver<Object> test2 = subject.test();
	System.out.println(test.values()); // received onNext values
	try {
		// Assert whether to receive subscription, but no event is sent
		test.assertEmpty();
		test2.assertEmpty();
		// Assert whether to receive onComplete()
		test.assertComplete();
		// Assert no data 100 sent
		test.assertNever(100);
		// Assert receive data results
		test.assertResult(1, 2, 3);
		// Assertion exception
		test.assertError(NullPointerException.class);
		... For more information, please refer to Api
	} catch (Error e) {
		System.out.println("Error: " + e);
	}

Output (in case of assertion mismatch, corresponding Error will be thrown):

--> onSubscribe:
--> onNext: 1
--> onNext: 2
--> onNext: 3
--> onNext: 100
--> onError: java.lang.NullPointerException
Error: java.lang.AssertionError: Value counts differ; expected: 0 but was: 4 (latch = 0, values = 4, errors = 1, completions = 0)
-----------------------------------------------
[1, 2, 3, 100]
Error: java.lang.AssertionError: Value counts differ; expected: 0 but was: 4 (latch = 0, values = 4, errors = 1, completions = 0)

Javadoc: TestObserver

6.8 Processor

Process and Subject have the same function and use. Process is a new function in Rxjava2. It is an interface inherited from Subscriber and Publish. The biggest difference with Subject is that process supports back pressure. As for back pressure, there will be a special article to give a detailed introduction.

7. Scheduler

If you want to add multithreading to the Observable operator chain, you can specify the operator (or a specific Observable) to execute on a specific scheduler.

Some ReactiveX Observable operators have variations that accept a Scheduler parameter. This parameter specifies the operator to place some or all of their tasks on a specific Scheduler.

With the observaon and SubscribeOn operators, you can make Observable execute on a specific scheduler. Observaon indicates that an Observable calls the observer's onNext, onError and onCompleted methods on a specific scheduler. SubscribeOn further indicates that Observable places all processing (including transmitting data and notifications) on a specific scheduler Execution.

Types of schedulers

The following table shows the types of schedulers available in RxJava:

Scheduler type Effect
Schedulers.computation() Used to calculate tasks, such as event loops or callback processing, not IO operations (use schedulers. Io(), for IO operations). The default number of threads is equal to the number of processors.
Schedulers.from(executor) Uses the specified Executor as the scheduler.
Schedulers.trampoline() Scheduled to work on the current thread, but not immediately. When other queued tasks are completed, the current thread is queued for execution.
Schedulers.io() For IO intensive tasks, such as asynchronous blocking of IO operations, the thread pool of this scheduler will grow as needed; for ordinary computing tasks, please use schedulers. Calculation(); Schedulers.io( ) is a CachedThreadScheduler by default, much like a new thread scheduler with thread cache.
Schedulers.newThread() Create a new thread for each task
Schedulers.single() A default, shared, single thread supported scheduler instance for work that needs to be performed in a strong sequence on the same background thread.

About the thread model, thread conversion operation and the use of scheduler in Rxjava, there will be a special article to introduce in detail.

Summary:

This chapter mainly introduces the concept and use dependency of Rxjava, the observer mode, Observable, Flowable, Subject, Schedule and other basic objects in Rxjava. It should be able to have a basic understanding and understanding of the concept and basic objects of Rxjava, as well as the simple use.

For other related parts of Rxjava2, there will be a series of articles in the future. Please pay attention to the real-time article directory above.

Topics: Mobile Java Programming github Android