A common question most android developers have when using RxJava is: how do I cache or persist the work done by my observables over a configuration change? If you start a network call and the user decides to rotate the screen, the work spent in executing that network call would have been in vain (considering the OS would re-create your activity).
There are two widely accepted solutions to this problem:
- store the observable somewhere as a singleton, possibly apply the cache operator and re-subscribe on activity recreation
- house your observable in a retained “worker” fragments 1
I whipped up a quick example on github to demonstrate the second technique (which is generally my choice of poison). Now I’ve used the technique of worker fragments (successfully) a bunch of times before so I was a little surprised to see the example not work.
Let’s go over the use case again:
You have an observable that executes a long running network call. Before the call completes, you perform an activity rotation. After the activity is recreated, you continue the network call from where it left off or just use the result if it completes before your activity recreation process.
Instead of simulating this network call use case I decided to just fake it with a “hot” observable instead (which makes the use case a tad bit different but would help demonstrate the solution equally well). If you’re looking for a quick simple example that demonstrates the difference between a hot and cold observable, I strongly recommend watching this egghead.io video on the subject.
In fact, I used the exact same concoction of operators for my example:
A little more investigation revealed that the share operator I used to fake the source stream was not really hot but “warm”. This is easier explained with Marble diagrams:
Here’s how we expect share to behave (and it does):
But owing to the activity recreation, what really happens is that the first subscriber (S1) unsubscribes from the source observable (O1 - housed in the worker fragment), after which a similar subscriber (S2) from the recreated activity subscribes again to O1 from the same worker fragment. So the marble diagram really lands up looking like this:
Notice that re-subscription? That changes things a little.
In this way, the share operator is “warm”. It behaves cold to first time subscribers but hot to subsequent ones.
the share operator behaves cold to first time subscribers but hot to subsequent ones
So how did I circumvent the problem? I added a fake subscriber that never unsubscribes.
Clever but very hacky2. Think carefully before you write code like this in production.
Epilogue (Part 2):
replay is hot to the first subscriber and cold to every other subscriber after the first item emits
Because marble diagrams are amazing:
I’ve since modified the example to use a ConnectableObservable instead and it works pretty much the same way.