Save your backend from a responsive UI using RxJava

Ricardo Belchior
3 min readAug 11, 2017

--

In this article I will describe one solution on a comments voting feature to prevent making too much network requests, while keeping your UI responsive.

Lately I’ve been implementing a Commenting feature in our Android app for the Daily Mirror Newspaper (link to Google Play), alongside with a Like/Dislike voting mechanism. Similarly to Reddit, you can vote for a LIKE, DISLIKE and NONE:

voting example

Typically when doing a network request on Android one has to:

  1. Start asynchronous work
  2. Wait for network response
  3. Update UI accordingly (success or error scenarios)

Literally following this pattern would make the UX a bit boring and so I followed an approach suggested by Yigit Boyar in this talk on designing offline-first applications. This can also be viewed as taking an optimistic approach on UX (https://uxplanet.org/optimistic-1000-34d9eefe4c05)

With this approach our UI updates its state immediately after user-clicks and the network requests are queued and performed at a later time. Network requests are expected to finish (most of the times) successfully with the help of Job Priority Queue library. When they don’t, the UI will simply revert gracefully to whatever it was before.

The problem we still had with this approach was that, in case the user starts spamming (pressing continuously) the likes/dislikes, the backend service for the voting system started to poop 💩💩💩 — it could not handle well all the requests happening quickly.

spamming all the votes

This is where we turned to RxJava for filtering unnecessary network requests. Assuming all LIKE, DISLIKE and NONE clicks (aka VoteAction) from all comments are handled in the same chain of events, this is how we handle it:

Get the last VoteAction per each comment

In the context of our problem, we only care about the last vote done by the user on each comment. Therefore assuming a continuous chain of VoteActions , this translates to:

last operation is a flatMap, so we return an Observable and keep working on the chain later on

Buffer VoteActions on a fixed period of time

Returning the last VoteAction per comment already filters most unnecessary network requests, the last bit is to buffer all requests on a fixed period of time. This allows all events to be collected during some time and only be processed in batches.

Note we’re able to do this as timing is not of utmost importance in this problem

Wrapping up

By buffering all VoteActions, we’re able to batch the click events and only process them after a fixed period of time. Then, we only keep the last VoteAction per each Comment. Finally, we apply a flatMap to transform the VoteAction into a “Job” that performs the actual network request.

The final solution took a bit of refactoring, to enable us to unit-test both operations. Here it is:

(ignoring subscribeOn/observeOn for demo purposes)
after some refactoring

This is only one of many possible solutions, one that worked for us. Feel free to give some feedback in case you like it or if you find any inconsistency!

--

--

Responses (5)