Improving UX with RxJava

Dionysis Lorentzos
Dionysis’ desk
Published in
3 min readNov 15, 2015

--

In a perfect mobile world users would never lose connectivity, servers will never return errors and bacon would have been low fat.

Search list animation by Daley P Maasz from Dribbble.

Building a great app experience is usually a bliss for a user but pain for the developer. Gone are the days that a user clicks a button, the UI gets blocked and you wait for a backend response. It’s just frustrating.

Let’s create today a better search functionality with an Editext and focus on the following:

  • As few network requests as possible
  • As few error messages to the user

The RX logic is quite simple and focuses in perfecting minor details.

Let’s start with the basic logic:

Whenever the user types something we perform a network call and then we get the results:

RxTextView.textChanges(searchEditText)
.flatMap(Api::searchItems)
.subscribe(this::updateList, t->showError());

1. Reduce network requests.

The above has two problems:

  1. you make a request per letter (yes that’s bad) e.g.: user types quickly “a”, then “ab” then “abc” then corrects to “ab” and want to search finally for “abe”. You have made 5 network requests. Imagine if there is slow internet connectivity.
  2. you have a threading race possible problem e.g: user types “a”, then “ab”. The network call for the “ab” comes first and the call for “a” second. In that case the last updateList() will get executed with results from the “a”.

Solutions:

  1. Add throttling behaviour:

debounce() is what you usually need. Values between 100–150 millis from my experience work the best. If your server needs additionally another 300ms then you can do a UI update in under 0,5 seconds.

RxTextView.textChanges(searchEditText)
.debounce(150, MILLISECONDS)
.flatMap(Api::searchItems)
.subscribe(this::updateList, t->showError());

2. Kill the previous requests:

introduce switchMap instead of flatMap. It will stop the previously emitted items. So if in time 0+150ms you search for “ab” and in time 0+300ms you search for “abcd” but the “ab” network call needs more than 150ms to complete, then by the time you start the “abcd” call the previous one will get canceled and you will always have the most recent result.

RxTextView.textChanges(searchEditText)
.debounce(150, MILLISECONDS)
.switchMap(Api::searchItems)
.subscribe(this::updateList, t->showError());

2. No error functionality / no network functionality

If a network call fails, you will never again observe text changes.

This can be easily solved by adding some error catching functionality.

So you could just use:

RxTextView.textChanges(searchEditText)
.debounce(150, MILLISECONDS)
.switchMap(Api::searchItems)
.onErrorResumeNext(t-> empty())
.subscribe(this::updateList);

Don’t do that. Let’s make it smarter. What if the searchItems() api call above calls because of connectivity? Or even more “UX-depressingly” brief connectivity that the user didn’t notice?

You need a retry mechanism for these:

RxTextView.textChanges(searchEditText)
.debounce(150, MILLISECONDS)
.switchMap(Api::searchItems)
.retryWhen(new RetryWithConnectivity())
.subscribe(this::updateList, t->showError());

How to improve it even further? By adding a timeout. As our (car2go) UX designer

says, “1 second is a lot of time in the user world”. So the above should be something like:

RxTextView.textChanges(searchEditText)
.debounce(150, MILLISECONDS)
.switchMap(Api::searchItems)
.retryWhen(new RetryWithConnectivityIncremental(context, 5, 15, SECONDS))
.subscribe(this::updateList, t->showErrorToUser());

So what will RetryWithConnectivityIncremental vs RetryWithConnectivity do? It will wait 5 seconds the phone to have internet, if more it will throw an exception. If the user retries it will wait with a longer timeout (e.g. 15 seconds).

Here is the code:

So there, you have it! You throttle your request, you have always the latest results, you have a retry on connectivity mechanism with a smart timeout.

The users will never notice, that’s a good design. ;)

Thank you for reading!

Want to learn more about me? I’m Dionysis, an Android dev at ShareNow + Founder of Nutech, a jobs app only for Android developers.

If you are an Android developer, you will most likely be interested in Nutech app.

--

--

Dionysis Lorentzos
Dionysis’ desk

Dionysis is an Android dev ShareNow + Founder of Nutech, a jobs app only for Android developers. He is passionate about auto industry innovation & space