RxJava 2 | Android : How to properly handle rotations with ConnectableObservable & Loader
If you’ve ever developed an Android application with RxJava, you’ve probably been exposed to rotation problems...
Indeed, when your Activity or Fragment is destroyed (during a rotation for example), Observables are, most of the time, manually unsubscribed (inside onDestroy()) to avoid memory leaks or unexpected behaviors.
What if we wanted to handle rotations in a better way ?
What if we wanted to resume a task STARTED in portrait and ENDED in landscape ? (So AFTER a rotation…) 🙌
I’ve looked all around the internet, and found out two concepts that, in my opinion at least, could solve this annoying problem:
- Loaders: Basically, Loaders are responsible for performing queries on a separate thread, monitoring the data source for changes, and delivering new results to a registered listener (usually the LoaderManager) when changes are detected.
- ConnectableObservable: A ConnectableObservable resembles an ordinary Observable, except that it does not begin emitting items when it is subscribed to, but only when its connect() method is called. In this way you can wait for all intended Subscribers to Observable.subscribe() to the Observable before the Observable begins emitting items.
Can you see what’s going to happen… 😉
Don’t worry and let’s practice ! Here is a preview of the final result :
1. Creating Disposable
For to start, we will create a Disposable to unsubscribe Observable when a Fragment is destroyed and prevent us from “temporary” memory leaks :
2. Creating Observable and Subscriber
To perform a long action, we will create an Observable (
getObservable()) that will wait 10 seconds before emitting a string (“Long process is ended !”). Then, we will listen to it with the Subscriber (
We will also update the TextView when the task starts and stops…
So far, so good in the RxJava world! 😃 You will get used to it.
Now, the tricky part. We will launch our previous long task, but instead of using a regular Observable, we will use… a ConnectableObservable, of course. And this one will allow us to subscribe it without launching it immediately!
Furthermore, we will put this observable in a Loader to better support it through various activities or fragments lifecycle events, such as
onDestroy() and configuration changes (rotation for example).
3. Creating Generic Loader
First of all, we will have to create the Loader into a dedicated class, RxJavaLoader.java. This one is pretty generic, so you can use and reuse it through all of your projects.
4. Executing and Resuming Observable
Now, let’s go back to MainFragment. When the user clicks on the button, it will launch the Observable and place it into a Loader (with
compose() method). And finally, the magic happens… 😉
We try, inside
onCreateView(), to resume and link any observable previously launched, asking the LoaderManager to get corresponding loader! If we find one, we will subscribe it (without launching it, that’s all the purposes of ConnectableObservable) and continue the task.
That’s all folks ! Try this on your own, and share your feelings about this approach 😄
You can find the demo project in my Github.