The two previous methods, zip()
and merge()
, work in the domain of the emitted items. There are scenarios in which we have to also consider the time before deciding how to operate on values. RxJava's join()
function combines items from two Observables, working with time windows.
To properly understand the previous figure, let's explain which parameters join()
takes:
Func1
parameter that returns an Observable that specifies a time span defining the time window during which the item emitted by the source Observable will interact with the items from the second ObservableFunc1
parameter that returns an Observable that specifies a time span defining the time window during which the item emitted by the second Observable will interact with the items from the source ObservableFunc2
parameter that defines how the emitted items will be combined together to emit a new itemAs a practical example, we can modify our loadList()
function like this:
private void loadList(List<AppInfo> apps) { mRecyclerView.setVisibility(View.VISIBLE); Observable<AppInfo> appsSequence = Observable.interval(1000, TimeUnit.MILLISECONDS).map(position -> { return apps.get(position.intValue()); }); Observable<Long> 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<AppInfo>() { @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); intposition = mAddedApps.size() - 1; mAdapter.addApplication(position, appInfo); mRecyclerView.smoothScrollToPosition(position); } }); }
We have a new player on the field: appsSequence
. This is an Observable sequence emitting apps from our installed apps list every second. The tictoc
Observable
item is just emitting a new Long
item every second. Joining them, we specify two Func1
variables:
appInfo -> Observable.timer(2, TimeUnit.SECONDS)
and
time -> Observable.timer(0, TimeUnit.SECONDS)
These describe the two time windows. The following line describes how we are going to combine the emitted values using a Func2
variable:
this::updateTitle
As a result, we have:
It looks a bit messy, but paying attention to the apps' names and the time windows we specified, we can see what's going on: we are combining the second item with the source item every time the second item is emitted, but we are using the same source item for 2 seconds. This is why the titles repeat themselves and the numbers add up.
It's worth mentioning, to lighten up the situation, that there is also a join()
operator that works on strings and simply joins the emitted strings into one final string:
3.141.35.185