In this section, we are going to show a few examples based on RxJava's just()
, repeat()
, defer()
, range()
, interval()
, and timer()
methods.
Let's assume we only have three separated AppInfo
objects and we want to convert them into an Observable and populate our RecyclerView
item:
List<AppInfo> apps = ApplicationsList.getInstance().getList(); AppInfo appOne = apps.get(0); AppInfo appTwo = apps.get(10); AppInfo appThree = apps.get(24); loadApps(appOne, appTwo, appThree);
We can retrieve the list like we did in the previous example and extract only three elements. Then, we pass them to the loadApps()
function:
private void loadApps(AppInfo appOne, AppInfo appTwo, AppInfo appThree) { mRecyclerView.setVisibility(View.VISIBLE); Observable.just(appOne, appTwo, appThree) .subscribe(new Observer<AppInfo>() { @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(), "Something went wrong!", Toast.LENGTH_SHORT).show(); mSwipeRefreshLayout.setRefreshing(false); } @Override public void onNext(AppInfo appInfo) { mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } }); }
As you can see, the code is very similar to the previous example. This approach gives you the opportunity to think about code reuse.
You can even pass a function as a parameter to the just()
method and you will have a raw Observable version of the existing code. Migrating from an existing code base to a new reactive architecture, this approach can be a useful point of start.
Let's assume you want to repeat the items emitted by an Observable three times. For example, we will use the Observable in the just()
example:
private void loadApps(AppInfo appOne, AppInfo appTwo, AppInfo appThree) { mRecyclerView.setVisibility(View.VISIBLE); Observable.just(appOne, appTwo, appThree) .repeat(3) .subscribe(new Observer<AppInfo>() { @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(), "Something went wrong!", Toast.LENGTH_SHORT).show(); mSwipeRefreshLayout.setRefreshing(false); } @Override public void onNext(AppInfo appInfo) { mAddedApps.add(appInfo); mAdapter.addApplication(mAddedApps.size() - 1, appInfo); } }); }
As you can see, appending repeat(3)
after the just()
Observable creation call will create a sequence of nine items, every one emitted singularly.
There can be scenarios where you want to declare an Observable but you want to defer its creation until an Observer subscribes. Let's say we have this getInt()
function:
private Observable<Integer> getInt() { return Observable.create(subscriber -> { if (subscriber.isUnsubscribed()) { return; } App.L.debug("GETINT"); subscriber.onNext(42); subscriber.onCompleted(); }); }
This is pretty simple and it doesn't really do much, but it will serve the purpose properly. Now, we can create a new Observable and apply defer()
:
Observable<Integer> deferred = Observable.defer(this::getInt);
At this time, deferred
exists, but the getInt() create()
method hasn't been called yet: there is no "GETINT"
in our logcat log:
deferred.subscribe(number -> { App.L.debug(String.valueOf(number)); });
But the moment we subscribe, create()
gets called and we get two new lines in our logcat
log: GETINT
and 42
.
Do you need to emit N integers from a specific starting number X? You can use range
:
Observable.range(10, 3) .subscribe(new Observer<Integer>() { @Override public void onCompleted() { Toast.makeText(getActivity(), "Yeaaah!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(Integer number) { Toast.makeText(getActivity(), "I say " + number, Toast.LENGTH_SHORT).show(); } });
The range()
function takes two numbers as parameters: the first one is the starting point, and the second one is the amount of numbers we want to emit.
The interval()
function comes in very handy when you have to create a polling routine:
Subscription stopMePlease = Observable.interval(3, TimeUnit.SECONDS) .subscribe(new Observer<Integer>() { @Override public void onCompleted() { Toast.makeText(getActivity(), "Yeaaah!", Toast.LENGTH_LONG).show(); } @Override public void onError(Throwable e) { Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show(); } @Override public void onNext(Integer number) { Toast.makeText(getActivity(), "I say " + number, Toast.LENGTH_SHORT).show(); } });
The interval()
function takes two parameters: a number that specifies the amount of time between two emissions, and the unit of time to be used.
If you need an Observable that emits after a span of time, you can use timer()
like in the following example:
Observable.timer(3, TimeUnit.SECONDS) .subscribe(new Observer<Long>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Long number) { Log.d("RXJAVA", "I say " + number); } });
This will emit 0
after 3 seconds, and then it will compete. Let's use timer()
with a third parameter, like the following example:
Observable.timer(3, 3, TimeUnit.SECONDS) .subscribe(new Observer<Long>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(Long number) { Log.d("RXJAVA", "I say " + number); } });
With this code, you can create a version of interval()
that starts with an initial delay (3 seconds in the previous example) and then keeps on emitting a new number every N seconds (3
in the previous example).
3.142.173.238