- The original is from "RxJava Essentials"
- Original Author: Ivan Morgillo
- Development technology Front www.devtf.cn
- Reprint statement: This translation has authorized developers to enjoy the exclusive right to reprint, without permission, not reproduced!
- Translator: Yuxingxin
- Project Address: RXJAVA-ESSENTIALS-CN
Why the observables?
In an object-oriented architecture, developers are committed to creating a set of decoupled entities. In this case, the entity can be tested, reused, and maintained without interfering with the entire system. Designing such a system has a tricky negative impact: maintaining unity among related objects.
In the Smalltalk MVC architecture, the first example of creating a pattern is to solve this problem. The user interface framework provides a way to separate UI elements from entity objects that contain data, and at the same time provides a flexible way to maintain synchronization between them.
The Observer pattern is one of the most well-known design patterns in the book "Design patterns – the basis for reusable object-oriented software", written in this popular four-person group. It is a behavior pattern and provides a way to bind an object with a one-to-many dependency: that is, when an object changes, all objects that depend on it are notified and automatically updated.
In this chapter, we will have an overview of the Observer pattern, how it is implemented and how to extend it with Rxjava, what observable is, and how observables is associated with Iterables.
Observer pattern
Today, the Observer pattern is one of the most common software design patterns that appear. It is based on the concept of subject. Subject is a special object that, when changed, will be notified of the series of objects that it saves. This series of objects is called observers, and they leak a notification method that will be called when the subject state changes.
In the previous chapter, we saw an example of an electronic form. Now we can unfold this example to show a more complex scenario. Let's consider such an electronic form filled with account data. We can compare this data to a table, a 3D histogram, or a pie chart. The meaning of each of these representatives depends on the data that the same group will present. Each is an observer who relies on the subject to maintain all the information.
3D histogram This class, the pie chart class, the table class, and the classes that maintain the data are completely decoupled: they are reused independently of each other, but can work together. These represent classes that are unclear to each other, but as they do: they know where to find the information they need to show, and they know that the class that needs to be updated when the data is changed.
Here's a picture of how a subject/observer relationship is a one-to-many relationship:
The above diagram shows a subject service for 3 observers. Obviously, there is no reason to limit the number of observers: if necessary, a subject can have an unlimited number of observers, and each of these observers will be notified when the subject state changes.
When do you use Observer mode?
The Observer pattern works well for any of the following scenarios:
- When your architecture has two entity classes, one depends on the other, and you want them to not affect each other or to reuse them independently.
- When a changing object notifies an unknown number of objects associated with its own change.
- When a changing object notifies those objects that do not need to infer a specific type.
Rxjava Viewer Mode Toolkit
In the world of Rxjava, we have four roles:
* Observable
* Observer
* Subscriber
* Subjects
Observables and subjects are two "production" entities, and observers and Subscribers are two "consumption" entities.
Observable
When we perform some complex things asynchronously, Java provides traditional classes such as thread, future, Futuretask, completablefuture to handle these problems. When complexity increases, these scenarios become cumbersome and difficult to maintain. Worst of all, they do not support chained calls.
RxJava Observables is designed to solve these problems. They are flexible and easy to use, can also be chained, and can be used on a single result program, or even on a sequence. You can use observable whenever you want to launch a single scalar value, or a series of values, or even an infinite number of streams.
The life cycle of the observable contains three possible events that are easy to compare with iterable life cycle events, and the following table shows how observable Async/push is associated with iterable Sync/pull.
Event |
iterable (Pull) |
Observable (push) |
Retrieving data |
T next() |
onNext(T) |
Error found |
throws Exception |
onError(Throwable) |
Complete |
!hasNext() |
onCompleted() |
When using iterable, the consumer gets the value from the producer in a synchronized manner, which is in a blocking state at these worthwhile front threads. Conversely, when using observable, the producer pushes the value to the observer asynchronously, whenever the value is available. This approach is more flexible because even if the value is reached synchronously or asynchronously, consumers can handle both scenarios according to their own needs.
To better reuse the Iterable interface, the RxJava observable class extends the semantics of the Gof observer pattern. Two new interfaces were introduced:
* OnCompleted () Notifies the Observer that observable no more data.
* OnError () that the Observer has an error occurred.
Hot observables and cold observables
From the point of view of the emitter, there are two different kinds of observables: hot and cold. A "hot" observable typically starts firing data as soon as it is created, so all subsequent subscribers to its observer may start accepting data from somewhere in the middle of the sequence (some data is missing). A "cold" observable will wait until an observer subscribes to it to start transmitting data, so the observer can ensure that the entire data sequence is received.
Create a observable
The two methods provided by observables to create observable are discussed in the next sections.
Observable.create ()
The Create () method gives developers the ability to create a observable from scratch. It requires an Onsubscribe object, which inherits Action1, and when the observer subscribes to our observable, it passes in as a parameter and executes the call () function.
Observable.create(new Observable.OnSubscribe<Object>(){ @Override publicvoidcallsuper Object> subscriber) { }});
Observable communicates with the observer by using the Subscriber variable and invoking its method according to the condition. Let's look at a "real world" example:
observable<integer> observablestring = Observable.create (NewObservable.onsubscribe<integer> () {@Override Public void Pager(SUBSCRIBER<?SuperInteger> observer) { for(inti =0; I <5; i++) {observer.onnext (i); } observer.oncompleted (); }}); Subscription Subscriptionprint = Observablestring.subscribe (NewObserver<integer> () {@Override Public void oncompleted() {System.out.println ("Observable completed"); }@Override Public void OnError(Throwable e) {System.out.println ("oh,no! Something wrong happened! "); }@Override Public void OnNext(Integer Item) {System.out.println ("Item is"+ Item); }});
The example is written deliberately, because even if you first see Rxjava, I want you to understand what's going to happen next.
We create a new one Observable<Integer>
, which executes 5 elements of the For loop, one after another to launch them, and finally finish.
On the other hand, we subscribed to observable and returned a subscription
。 Once we subscribe, we begin to accept integers and print them out one after the other. We don't know how many integers to accept. In fact, we don't need to know because we have a corresponding processing operation for each scenario:
* If we receive an integer, then print it.
* If the sequence ends, we will print a closed sequence of information.
* If an error occurs, we will print an error message.
Observable.from ()
In the previous example, we created a sequence of integers and emitted them one after another. What if we already have a list? Can we launch them one after the other without a for-loop?
In the example code below, we create a observable sequence from an existing list:
list<integer> items =NewArraylist<integer> (); Items.Add (1); Items.Add (Ten); Items.Add ( -); Items.Add ( $);observable<integer> observablestring = observable.from (items); Subscription Subscriptionprint = Observablestring.subscribe (NewObserver<integer> () {@Override Public void oncompleted() {System.out.println ("Observable completed"); }@Override Public void OnError(Throwable e) {System.out.println ("oh,no! Something wrong happened! "); }@Override Public void OnNext(Integer Item) {System.out.println ("Item is"+ Item); }});
The result of the output is absolutely the same as the example above.
from()
The creator can create a observable from a list/array and emit each object from a list/array one after another, or you can create a observable from the Java Future
class and emit .get()
The result value returned by the method of the future object. Future
when passed in as a parameter, we can specify a time-out value. Observable will wait for Future
the result to come from, and if there is still no result returned before the timeout, observable will trigger the onError()
method to notify the Observer that an error has occurred.
Observable.just ()
What if we had a traditional Java function and we wanted to turn it into a observable and change it? We can use the create()
method, as we saw earlier, or we can use it as follows to save a lot of template code:
observable<string> observablestring = Observable.just (HelloWorld ()); Subscription Subscriptionprint = Observablestring.subscribe (NewObserver<string> () {@Override Public void oncompleted() {System.out.println ("Observable completed"); }@Override Public void OnError(Throwable e) {System.out.println ("oh,no! Something wrong happened! "); }@Override Public void OnNext(String message) {System.out.println (message); }});
helloWorld()
The method is relatively simple, like this:
privatehelloWorld(){ return"Hello World";}
Anyway, it can be any function we want. In our example, once we have created observable and executed the just()
function, when we subscribe to observable, it emits the returned value.
just()
The method can pass in one to nine parameters, which emit them in the order in which they are passed in. The just()
method can also accept a list or array, just like a from()
method, but it does not iterate through the list to emit each value, it will emit the entire list. Typically, it is used when we want to launch a set of values that are already defined. But if our function is not time-variant, we can use just to create a more organized and measurable code base.
Finally note that the just()
creator, after it emits the value, Observable the normal end, in the above example, we will print two messages in the console: "Hello World" and "Observable completed".
Observable.empty (), Observable.never (), and Observable.throw ()
When we need a observable no reason to no longer send the data to normal end, we can use empty()
. We can use to never()
create a observable that does not emit data and will never end. We can also use throw()
to create a observable that does not emit data and ends with an error.
Subject = Observable + Observer
subject
is a magical object, it can be a observable at the same time can also be a observer: it as a bridge connecting the two worlds. A subject can subscribe to a observable, like an observer, and it can emit new data, or pass the data it receives, like a observable. Obviously, as a observable, observers or other subject can subscribe to it.
Once subject subscribes to observable, it will trigger observable to start firing. If the original observable is "cold", this will have an impact on subscribing to a "hot" observable variable.
Rxjava offers four different types of subject:
* Publishsubject
* Behaviorsubject
* Replaysubject.
* Asyncsubject
Publishsubject
Publish is a basic subclass of subject. Let's take a look at the traditional observable with Publishsubject Hello World
:
publishsubject<string> stringpublishsubject = Publishsubject.create (); Subscription Subscriptionprint = Stringpublishsubject.subscribe (NewObserver<string> () {@Override Public void oncompleted() {System.out.println ("Observable completed"); }@Override Public void OnError(Throwable e) {System.out.println ("oh,no! Something wrong happened! "); }@Override Public void OnNext(String message) {System.out.println (message); }}); Stringpublishsubject.onnext ("Hello World");
In the example we have just created a PublishSubject
create()
method to emit a String
value, and then we subscribe to Publishsubject. At this point, there is no data to send, so our observers can only wait, not block threads, or consume resources. Right here, ready to receive the value from the subject, if the subject does not emit a value then our observer will be waiting. Again, there's no need to worry: The Observer knows what to do in each scene, and we don't have to worry about when it's responsive: the system responds. We don't care what time it responds. We only care what it does when it responds.
The last line of code shows the manual launch of the string "Hello World", which triggers the observer's onNext()
approach, allowing us to print "Hello World" information on the console.
Let's look at a more complex example. In other words we have a private
statement that the observable cannot be accessed externally. Observable emit values in its life cycle, we don't care about these values, we only care about their end.
First, we create a new publishsubject to respond to its onNext()
approach, and it can be accessed externally as well.
final PublishSubject<Boolean> subject = PublishSubject.create();subject.subscribe(new Observer<Boolean>() { @Override publicvoidonCompleted() { } @Override publicvoidonError(Throwable e) { } @Override publicvoidonNext(Boolean aBoolean) { System.out.println("Observable Completed"); }});
We then create a "private" observable that only subject can access.
observable.create (new observable.onsubscribe<integer> () { @Override public void call (subscriber <? super integer> subscriber) {for (int i = 0 ; I < 5 ; i++) {subscriber.onnext (i); } subscriber.oncompleted (); }}). dooncompleted (new Action0 () { @Override public void Call () {Subject.onnext (true ); }}). Subscribe ();
Observable.create()
The method contains the familiar for loop, which emits the number. doOnCompleted()
The Observable method specifies what to do when the end of the event is completed: Firing true on subject. Finally, we subscribed to the observable. Obviously, an empty subscribe()
call is simply to open observable, without having to control any value that has been emitted, or to complete an event or error event. For this example we need it like this.
In this example, we create an entity that can be connected to observables and can be observed at the same time. This is extremely useful when we want to create independent, abstract, or easier-to-observe points for public resources.
Behaviorsubject
Simply put, Behaviorsubject will first send his subscribers the latest data object (or initial value) as of the pre-subscription, and then send the subscribed data stream normally.
BehaviorSubject<Integer> behaviorSubject = BehaviorSubject.create(1);
In this short example, we created a behaviorsubject that can emit plastic (integer). Because the latest data is emitted whenever observes subscribes to it, it requires an initial value.
Replaysubject
Replaysubject caches all the data it subscribes to and re-sends it to any observer who subscribes to it:
ReplaySubject<Integer> replaySubject = ReplaySubject.create();
Asyncsubject
When observable is complete asyncsubject will only publish the last data to each observer who has subscribed.
AsyncSubject<Integer> asyncSubject = AsyncSubject.create();
Summarize
In this chapter, we learned what observer patterns are, why observables is so important in today's programming scenarios, and how to create observables and subjects.
In the next chapter, we will create the first Rxjava-based android application, learn how to retrieve data to populate the ListView, and explore how to create a Rxjava-based responsive UI.
Rxjava Development Essentials 2-why observables?