RxJava development essentials 6-combination of Observables
In the previous chapter, we learned how to convert observability sequences. We also sawmap()
,scan()
,groupBY()
And more examples of useful functions. They help us operate the Observable to create the Observable we want.
In this chapter, we will study combined functions and learn how to process multiple Observables at the same time to create the desired Observable.
Merge
This scenario is often created in an asynchronous world. We have multiple sources but only want to have one result: multiple inputs and single outputs. RxJavamerge()
The method will help you merge two or more Observables into the data they are launching. The combination of the two sequences in a final transmitted Observable is given.
As you can see, the transmitted data is merged into an Observable. Note that if you synchronize the merged Observable, they will be connected together and will not cross. <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4NCjxwPs/issue + uq/K/c/xz8ld5txi0fmjuw.vcd4ncjxwcmugy2xhc3m9 "brush: java;"> private void loadList(List apps) { mRecyclerView.setVisibility(View.VISIBLE); List reversedApps = Lists.reverse(apps); Observable observableApps =Observable.from(apps); Observable observableReversedApps =Observable.from(reversedApps); Observable mergedObserbable = Observable.merge(observableApps,observableReversedApps); mergedObserbable.subscribe(new Observer(){ @Override public void onCompleted() { mSwipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { Toast.makeText(getActivity(), "One of the two Observable threw an error!", Toast.LENGTH_SHORT).show(); mSwipeRefreshLayout.setRefreshing(false); } @Override public void onNext(AppInfoappInfo) { mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } });}
We have created the Observable and observableApps data and the new observableReversedApps reverse list. UseObservable.merge()
, We can create a newObservableMergedObservable
All data sent from the source Observables in a single observability sequence.
As you can see, every method signature is the same, so our observers can reuse code without worrying about any difference. The result is as follows:
Note the toast message when an error occurs. You can think that the error thrown by each Observable will interrupt the merge. RxJava providesmergeDelayError()
It can continue to transmit data from an Observable, even if one of them throws an error. When all the Observables are completed,mergeDelayError()
Will launchonError()
, As shown in:
ZIP
When processing multiple sources, we may bring about such a scenario: receiving data from multiple Observables, processing them, and then merging them into a new observability sequence. RxJava has a special method to accomplish this:zip()
Merges two or more data items emitted by the Observables according to the specified function.Func*
Convert them and emit a new value. Shownzip()
How to deal with the released "numbers" and "letters" and then merge them into a new data item:
For the "real world" example, we will use the installed Application List and a new dynamic Observable to make the example a bit interesting.
Observable
tictoc = Observable.interval(1, TimeUnit.SECONDS);
tictoc
Observable variable usageinterval()
The function generates a Long data type per second: simple and efficient. As we mentioned earlier, we needFunc
Object. Because it requires two parametersFunc2
:
private AppInfo updateTitle(AppInfoappInfo, Long time) { appInfo.setName(time + " " + appInfo.getName()); return appInfo;}
Now ourloadList()
The function becomes like this:
private void loadList(List
apps) { mRecyclerView.setVisibility(View.VISIBLE); Observable observableApp = Observable.from(apps); Observable
tictoc = Observable.interval(1, TimeUnit.SECONDS); Observable.zip(observableApp, tictoc, (AppInfo appInfo, Long time) -> updateTitle(appInfo, time)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @Override public void onCompleted() { Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { mSwipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(AppInfoappInfo) { if (mSwipeRefreshLayout.isRefreshing()) { mSwipeRefreshLayout.setRefreshing(false); } mAddedApps.add(appInfo); int position = mAddedApps.size() - 1; mAdapter.addApplication(position, appInfo); mRecyclerView.smoothScrollToPosition(position); } });}
As you can see,zip()
The function has three parameters: Two Observables and oneFunc2
.
A closer look will show youobserveOn()
Function. It will be explained in the next chapter: now we can try it out.
The result is as follows:
Join
The first two methods,zip()
Andmerge()
Methods are used in the scope of data transmission. We need to consider time in some scenarios before deciding how to operate values. RxJavajoin()
The function combines the data transmitted by two Observables based on the time window.
For a correct understanding of the previous figure, we will explainjoin()
Required parameters:
The second Observable is combined with the source Observable.
Func1
Parameter: during the specified time interval defined by the time window, the data transmitted by the source Observable and the data transmitted from the second Observable work together to return the Observable.
Func1
Parameter: within the specified time interval defined by the time window, the data transmitted by the second Observable matches the data transmitted from the source Observable to the returned Observable.
Func2
Parameter: defines how the transmitted data is combined with the newly released data item.
For example, we can modify
loadList()
Functions are as follows:
private void loadList(List
apps) { mRecyclerView.setVisibility(View.VISIBLE); Observable appsSequence = Observable.interval(1000, TimeUnit.MILLISECONDS) .map(position -> { return apps.get(position.intValue()); }); Observable
tictoc = Observable.interval(1000,TimeUnit.MILLISECONDS); appsSequence.join( tictoc, appInfo -> Observable.timer(2,TimeUnit.SECONDS), time -> Observable.timer(0, TimeUnit.SECONDS), this::updateTitle) .observeOn(AndroidSchedulers.mainThread()) .take(10) .subscribe(new Observer() { @Override public void onCompleted() { Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { mSwipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(AppInfoappInfo) { if (mSwipeRefreshLayout.isRefreshing()) { mSwipeRefreshLayout.setRefreshing(false); } mAddedApps.add(appInfo); int position = mAddedApps.size() - 1; mAdapter.addApplication(position, appInfo); mRecyclerView.smoothScrollToPosition(position); } });}
We have a new object.appsSequence
It is an observability sequence that transmits app data from the list of installed apps per second.tictoc
This Observable data only emits one newLong
Type integer. To merge them, we need to specify twoFunc1
Variable:
appInfo -> Observable.timer(2, TimeUnit.SECONDS)time -> Observable.timer(0, TimeUnit.SECONDS)
Two time windows are described above. The following line describes how to useFunc2
Combine the two launch data.
this::updateTitle
The result is as follows:
It looks messy, but pay attention to the app name and the specified time window. We can see that once the second data is released, it will be combined with the source data, however, we use the same source data for 2 seconds. This is why repeated titles are accumulated.
It is worth mentioning that for the sake of simplicity, there is alsojoin()
The operator acts on the string and then simply connects to the transmitted string to form the final string.
CombineLatest
RxJavacombineLatest()
Functions look a bit likezip()
Special form of a function. As we have learned,zip()
It acts on two unpackaged Observables. On the contrary,combineLatest()
Act on recently released data items: IfObservable1
Launch A andObservable2
Launched B and C,combineLatest()
AB and AC will be grouped, as shown in:
combineLatest()
The function accepts two to nine Observable values as parameters, or a single Observables list as parameters if necessary.
In the previous exampleloadList()
If the function is borrowed, We can modify itcombineLatest()
The following example shows how to implement "real world:
private void loadList(List
apps) { mRecyclerView.setVisibility(View.VISIBLE); Observable appsSequence = Observable.interval(1000, TimeUnit.MILLISECONDS) .map(position ->apps.get(position.intValue())); Observable
tictoc = Observable.interval(1500, TimeUnit.MILLISECONDS); Observable.combineLatest(appsSequence, tictoc, this::updateTitle) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @Override public void onCompleted() { Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { mSwipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(AppInfoappInfo) { if (mSwipeRefreshLayout.isRefreshing()) { mSwipeRefreshLayout.setRefreshing(false); } mAddedApps.add(appInfo); int position = mAddedApps.size() - 1; mAdapter.addApplication(position, appInfo); mRecyclerView.smoothScrollToPosition(position); } });}
We use two Observables: one is to transmit an App data from the list of installed apps every second, and the other is to launch an App data every 1.5 seconds.Long
Type integer. We combine them and executeupdateTitle()
Function. The result is as follows:
As you can see, due to different time intervals,AppInfo
Objects are repeated as we expected.
And, Then And When
There will be morezip()
Scenarios that cannot be met. For example, you can use And/Then/When solutions for complex architectures or just for personal interests. Under RxJava's joins package, they use Pattern and Plan as the intermediary to merge the transmitted data sets together.
OurloadList()
The function will be modified from the following:
private void loadList(List
apps) { mRecyclerView.setVisibility(View.VISIBLE); Observable observableApp = Observable.from(apps); Observable
tictoc = Observable.interval(1, TimeUnit.SECONDS); Pattern2 pattern = JoinObservable.from(observableApp).and(tictoc); Plan0 plan = pattern.then(this::updateTitle); JoinObservable .when(plan) .toObservable() .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @Override public void onCompleted() { Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { mSwipeRefreshLayout.setRefreshing(false); Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(AppInfoappInfo) { if (mSwipeRefreshLayout.isRefreshing()) { mSwipeRefreshLayout.setRefreshing(false); } mAddedApps.add(appInfo); int position = mAddedApps.size() - 1; mAdapter.addApplication(position, appInfo); mRecyclerView.smoothScrollToPosition(position); } });}
Like in general, we have two emission sequences,observableApp
To launch the list of installed applications,tictoc
One per secondLong
Type integer. Now we useand()
Connect the source Observable and the second Observable.
JoinObservable.from(observableApp).and(tictoc);
Createpattern
Object. With this object, we can createPlan
Object: "We have two Observables for transmitting data,then()
What is it ?"
pattern.then(this::updateTitle);
Now we havePlan
And when the plan happens, we can decide what will happen next.
.when(plan).toObservable()
At this time, we can subscribe to the new Observable, as we always do.
Switch
In such a complex scenariosubscribe-unsubscribe
In the sequence, we can automatically unsubscribe from an Observable to subscribe to a new Observable.
RxJavaswitch()
, As defined, convert one Observable that emits multiple Observables into another independent Observable, which then emits the data items that have been recently released by the Observables.
A source Observable that transmits multiple Observables sequences is provided,switch()
Subscribe to the source Observable and start to transmit the same data from the first transmitted Observable. When the source Observable emits a new Observable,switch()
Immediately unsubscribe to the previous transmitted data's Observable (which interrupts the data stream from it), subscribe to a new Observable, and start to launch its data.
StartWith
We have learned how to connect multiple Observables and append the specified values to an emission sequence. RxJavastartWith()
Yesconcat()
. Asconcat()
Append data to the Observable of the data to be sent. Before the Observable starts to transmit their data,startWith()
Transmit a data sequence by passing a parameter.
Summary
In this chapter, we learned how to combine two or more Observable to create a new observability sequence. We will be ablemerge
Observable,join
Observables,zip
And combine them in several situations!