How to make Android more Rx — 5 tips & tricks

Paulina Szklarska
5 min readJun 10, 2017

If you’re using RxJava in your daily routine, probably one day you’ll reach the point where you want to… put RxJava everywhere! Let me give you 5 practical pieces of advice.

Using RxJava everywhere is not a bad idea (usually). It’s normal that you’re thinking “Hey, it’ll look a lot cooler if I could just put this in RxJava flow, instead of using for-loop/Handler/Async Task/some other ugly solution”. Yes, it’ll be cool. If only I could…

Well, I have some good news for you — with RxJava you can do most of the things you’ve ever dreamed of! Let me give you my 5 pieces of advices about the things I like and often use in my projects.

These code snippets will work both on RxJava and RxJava2. This article assumes you have some basic knowledge about RxJava. If not, I recommend you read some other articles first (this one on RxJava — the production line — makes for a great beginning).

#1 Double click detection

You have some buttons in your application and you want to detect if these buttons were clicked twice. Easy, isn’t it? Yes, all you need to do this is to make a counter, check for every click, move the counter up an increment and remember to reset the counter afterwards… No way, there must be a cleaner way to do this. Of course, here it is:

private PublishSubject<Boolean> eventSubject = PublishSubject.create();public static final int TIME_BETWEEN_EVENTS_MILLIS = 500;
public static final int NUMBER_OF_EVENTS = 2;
public DoubleClick() {
eventSubject
.buffer(eventSubject.debounce(TIME_BETWEEN_EVENTS_MILLIS,
TimeUnit.MILLISECONDS))
.filter(events -> events.size() == NUMBER_OF_EVENTS)
.subscribe(events -> doSomething());
button.setOnClickListener((button) ->
eventSubject.onNext(true));
}

By using PublishSubject, we can emit our own items and catch them. After catching, we check if the number of events is the same as the value we want. Of course, you can do it with every event — getting a text from TextView, getting clicks from any other View or anything else.

#2 Repeating requests to API every 10 minutes

Using operator repeatWhen , combined with delay results, can result in delaying our subscription after some time. If, for some reason, you’d like to request for new data from the API every 10 minutes, you can do it with RxJava in just one line:

sourceObservable.repeatWhen(completed -> completed.delay(10,
TimeUnit.MINUTES));

Just keep in mind, that Observable will only repeat if the previous one was completed.

#3 Combining two dependent objects

Let’s say we are receiving Cats from API, and, for every Cat, we’d like to get some Toys (which are dependent on Cat). After this, we want to have an object combined with CatAndToys — it’s possible to do this with RxJava using the second parameter of flatMap (what is not so commonly used), which

[…] combines items from the source Observable with the Observable triggered by those source items, emitting these combinations.

Source: RxJava documentation

Let the code speak for itself:

Observable<CatWithToys> catWithToysObservable = 
getCatObservable()
.flatMap((cat) -> getToysForCatObservable(cat),
(cat, toys) -> new CatWithToys(cat, toys));

We see this first parameter in flatMap takes Cat as a parameter and returns Toys. Then the second parameter takes Cat and Toys (the result from the first function) and returns the CatWithToys object. This way, you can combine many dependent requests to API without using nested flatMap operators.

#4 Request pagination

If you want to paginate through some objects from API, you can do it easily with RxJava. The trick is to merge all the pages until you achieve some final point (e.g. the last request gives you empty results, or the items count will be proper and correct). Let’s look at the code:

public Observable<List<User>> getAllUsers() {
return getUsersObservable(null);
}
private Observable<List<User>> getUsersObservable(final String
lastUserId) {
return apiAdapter
.getData(lastUserId)
.filter(userList -> !isLastPage(userList))
.flatMap(this::getNextPageUsersObservable);
}
private Observable<List<User>> getNextPageUsersObservable(final
List<User> userList) {

Observable<List<User>> usersPageObservable =
Observable.just(userList);
int lastUserId = getLastUserId(userList);
Observable<List<User>> nextUsersPageObservable =
getUsersObservable(lastUserId);
return Observable.merge(nextUsersPageObservable,
usersPageObservable);
}
private boolean isLastPage(final List<User> userList) {
return userList.isEmpty();
}

Firstly, we’re requesting for a single page without any parameter (or you can put 0 here, depending on your API), then we check our end list condition — if we didn’t reach the end, we’re requesting for some new pages with the parameter from the last request (it could be the last ID of the user, or a date of the newest photo, or anything else) and we will merge it with the previous Observable. If we reach the end of the list, we finish.

#5 Lightweight RxBus

If you’re using an event bus in your project (no matter if this is Otto, Event Bus from Greenrobot, or something else), you may be interested in implementing your own event bus — RxBus! You may be asking why we’re reinventing the wheel, instead of using something, that was made by someone else?

Well, when you see how easy implementing your own EventBus with RxJava is, you may rethink putting this in as an internal library. You’re independent of changes in the external library, so you can adjust RxBus to suit your needs and — if you already have RxJava in the project — why don’t you use it for something more?

public class RxBus {
private static final RxBus instance = new RxBus();
private final Subject<RxEvent> rxBus;
public RxBus() {
PublishSubject<RxEvent> rxEventPublishSubject =
PublishSubject.create();
rxBus = rxEventPublishSubject.toSerialized();
}
public static RxBus getInstance() {
return instance;
}
public Observable<RxEvent> getRxBus() {
return rxBus;
}
public void post(final RxEvent rxEvent) {
rxBus.onNext(rxEvent);
}
public class RxEvent {}
}

The main “core” of RxBus is SerializedSubject (very similar to PublishSubject, which we used to detect double clicks, but this one is thread-safe). We simply create a singleton class that holds a reference to this SerializedSubject. If we send some event, we emit items with SerializedSubject, if we subscribe to the event, we subscribe to receiving events from SerializedSubject. Simple, isn’t it? We use the toSerialized() method because we want to use our RxBus from different threads.

Conclusion

As you can see — there’s a lot of things you can do with RxJava. It’s helpful for views, data requesting and internal communication in your app. Remember, there are many solutions for the problems I presented and RxJava may not be always the best one, but I hope these tips inspired you to look for some other solutions for your issues.

That’s it! I hope you like my tips. Stay tuned for more!

--

--

Paulina Szklarska
Paulina Szklarska

Written by Paulina Szklarska

Flutter GDE / Flutter & Android Developer / blogger / speaker / cat owner / travel enthusiast

No responses yet