There are several situations in my codebase where a stream I'm subscribing to will only ever emit one result and as such it makes sense to use rx.Single rather than rx.Observable. The documentation for Single says the following:
A Single will call only one of these methods, and will only call it
once. Upon calling either method, the Single terminates and the
subscription to it ends.
With a traditional Observable I capture a reference to the Subscription so that I can unsubscribe at an appropriate time and not cause memory leaks:
Subscription s = getObservable().subscribe(...);
subscriptions.add(s);
subscriptions.clear();
My question is whether this is necessary with a Single or whether due to the fact that the subscription ends immediately it could be left simply as:
getSingle.subscribe(...);
Without any negative repercussions of references being held onto into the subscriber.
Single doesn't tell you anything about how long it will be running.
Since you're targeting Android, the answer is yes, you should keep the subscription and unsubscribe.
Imagine you're switching Fragments/Activities and a long running SingleSubscribers's onSuccess is called. So the best time and space is probably in onPause(), but it depends on your context.
You might run into NullPinterExceptions, Adapters being filled multiple times or similar problems if you don't unsubscribe.
Any reason why you need to cleanup the subscription on Observable?. Observable by design once that the observer has all items is automatically unsubscribed.
And then, since the instance is not reference anymore the GC at some point will clean up for you.
You can see in these example how the subscription is unsubscribe after onComplete is reach.
https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/creating/ObservableSubscription.java
Related
As launchWhenStarted and repeatOnLifecycle(STARTED) provide completely different functionality (launchWhenStarted suspends the execution of the coroutine, and repeatOnLifecycle cancels and restarts a new coroutine), if the names of the new APIs were similar (for example, using launchWhenever for the restarting APIs), developers could’ve got confused and even use them interchangeably without noticing.
source
What is a simpler explanation for when to use which?
launchWhenStarted is just a one-time delay.
repeatOnLifecycle creates a suspending point that acts as a handler that runs provided block every time the lifecycle enters provided state and cancels it whenever it falls below it (so for STARTED it happens when it gets stopped).
Update:
For more information: https://medium.com/androiddevelopers/repeatonlifecycle-api-design-story-8670d1a7d333
repeatOnLifecycle restarts its coroutine from scratch on each repeat, and cancels it each time lifecycle falls below the specified state. It’s a natural fit for collecting most flows, because it fully cancels the flow when it’s not needed, which saves resources related to the flow continuing to emit values.
launchWhenX doesn’t cancel the coroutine and restart it. It just postpones when it starts, and pauses execution while below the specified state. They plan to deprecate these functions but I suspect there will need to be some replacement if they do, for the case where you are calling some time consuming suspend function and then want to do something when it’s done, like starting a fragment transaction. Using repeatOnLifecycle for this would result in redoing the time consuming action.
A cold flow backed by a channel or using operators with buffers such as buffer, conflate, flowOn, or shareIn is not safe to collect with some of the existing APIs such as CoroutineScope.launch, Flow<T>.launchIn, or LifecycleCoroutineScope.launchWhenX, unless you manually cancel the Job that started the coroutine when the activity goes to the background. These APIs will keep the underlying flow producer active while emitting items into the buffer in the background, and thus wasting resources.
To solve this issue with these APIs, you’d need to manually cancel collection when the view goes to the background. but it sounds to be a boilerplate code.
That's why Google recommended repeatOnLifecycle(Lifecycle.State.XXX) to make it simple and safe.
repeatOnLifecycle is a suspend function that takes a Lifecycle.State as a parameter which is used to automatically create and launch a new coroutine with the block passed to it when the lifecycle reaches that state, and cancel the ongoing coroutine that’s executing the block when the lifecycle falls below the state.
Learn more from here
I've seen patterns like this:
Observable<String> nameChanges = nameDataSource.changes().share();
// One subscriber
autoUnsubscribe(nameChanges.subscribe(() -> { ... }));
// Another subscriber
autoUnsubscribe(nameChanges.map(...).filter(...).subscribe(...));
// autoUnsubscribe is called when the UI is torn down
My question is:
Why is it necessary to call share() whenever I want to listen to the Observable in multiple places?
Why is not share() the default behavior for all observables?
It would be nice if the code above worked the same even without .share(). I would not have to think about when I need to share an Observable, and when I don't.
Is it for performance reasons because having a single subscriber is a special case that can be handled more efficiently?
From the docs this is not clear to me:
share() returns a new ObservableSource that multicasts (shares) the original ObservableSource. As long there is at least one Observer this ObservableSource will be subscribed and emitting data.
There are two kinds of Observables: cold and hot. Cold Observables start producing items when there is an Observer to them and they do it on an individual basis. Subscribing with multiple Observers will result in multiple runs of the same cold Observable. An example of this is an Observable that issues a network request.
In contrast, a hot Observable can produce items with or without the presence of Observers. These Observables usually multicast the same items to all of their current Observers. An example of this is an Observable of button clicks.
To turn a cold Observable into a hot one, you can use publish() which will make sure only a single subscription is established to the source Observable no matter how many Observers there are. Thus, the chain will now act as a hot multicasting Observable from the Observers' perspective.
However, often it is not economic to keep an originally cold Observable running after all Observers of publish() have gone away, therefore the refCount() operator can be used to keep track of them and stop the source when there are no interesting parties left.
If your source is already hot, you don't need share().
Why is not share() the default behavior for all observables?
Actually, this property is one of the important contributions of the modern reactive programming paradigm: the distinction of the hot and cold Observables.
However, multicasting is expensive on itself because you have to keep track of the set of current Observers in order to notify them with new events, and this can lead to all sorts of logical race conditions to be defended against. A cold Observable is known to talk only to a single Observer so there is no need for the extra tracking overhead.
I would not have to think about when I need to share an Observable, and when I don't. I'm afraid that you will have to think when programming. ;)
In the above code, yes, sharing makes sense. But what if you we're updating something on the backend, using the same network and method call from two different points, updating with different data? You would have the same call with the same Observable, but you certainly wouldn't want to share the Observable instance (and the network call) because that means that all successive calls with data would be discarded in the favour of the first one. Or if you wanted to start a timer whenever you're subscribed, you again wouldn't want to share this with other Observables.
Also, it is much easier to add certain behaviour than to remove it. For example, if sharing was the default, and the second subscriber wouldn't want to share and removes the sharing - what about the third one? Will it share it with the first one or not? At that point the sharing property becomes the property of the Subscriber and not the Observable and you would have no clear way of knowing which one is shared and which one isn't.
I'm using the post-Google I/O 2016 Firebase database.
On a DatabaseReference, there is two similar methods, seem to only differ by the completion callback.
One is void setValue(Object value, DatabaseReference.CompletionListener listener), and another is Task<Void> setValue(Object value).
Are they interchangeable? The docs does not say anything about it and the Firebase Android SDK is closed source.
They are almost interchangeable. The key difference between the Task returned by setValue and the passed CompletionListener is the ability to avoid object leaks.
When you pass a CompletionListener to setValue, the Firebase SDK will hold on to that object reference (and all of that object's strong references, and so on) indefinitely, until the data is finally written at the server side. For Android apps, this can be particularly problematic because you could end up leaking an Activity reference, which is pretty expensive.
When you use a Task, you have the ability to add and remove listeners from that as needed, so if you're no longer interested in knowing if a write succeeded, you can free up the objects that were previously interested. In Android, there are overloads for adding listeners that automatically let a listener remove itself when the activity is stopped, so you don't have to arrange to do that yourself.
With Tasks, you can also arrange to have your callback invoked on a particular Executor, which is a convenient way to kick intense work off to another thread. With, CompletionListener, you'd have to arrange for that yourself in the callback itself.
I have a four-part blog series on the Tasks that are provided by Play services and the Java admin SDK. There is also formal documentation.
I work with RxJava and RxAndroid. How resume the work of an observable if a configuration change occurs (activity rotation, language locale change etc.)?
I need not only resume the work of an observable, also I need save emitted items, when subscriber is unsubscribed and emit all saved items right away after subscription.
I read a ton of articles, but I didn't find the answer to my question.
I found a few examples, but none of them does not solve the problem:
https://github.com/alapshin/rxweather
https://github.com/kaushikgopal/RxJava-Android-Samples
https://github.com/tehmou/rx-android-architecture
https://github.com/richardradics/RxAndroidBootstrap
You can use one of the ConnectableObservables. Particularly, cache or replay would be handy for this kind of situation.
For example, you can call cache on your observable, unsubscribe it when activity is destroyed, and resubscribe it again after the activity is recreated.
I have made a demo application (https://github.com/pmellaaho/RxApp) in order to experiment how to tackle these kinds of situations. Basically, I use a singleton model from Activity to get the response from network. This makes it possible to cache responses, access the data from multiple UI components, subscribe to pending request and also to provide mock data for automated UI tests.
You can use OperatorFreeze from this library for pausing Observable when activity is recreating. You need pass instance of this operator to method Observable.lift(). You don't need to unsubscribe from Observables when you use persistent Presenter.
Is it good practice to use Otto event bus bi-directionally?
I mean, send events from controller to view, and view to controller?
Or is it just meant to publish results meaning its purpose is only events from controller to view?
Thanks
Good question. Here is my thoughts on this. I use Otto for a while and use it bi-directionally. From my experience there is nothing against doing this. I have just defined couple of rules helping me keep everything under control.
One-to-many pattern must be confirmed. I mean here, that one producer should normally notify multiple subscribers. Of course, at different point in time there can be zero or more subscribers. But if you have a case, where by-design maximum number of subscribers is just one, then you trying to dispatch rather a "command", than an "event". For such cases I would use a direct call instead of posting a event.
Another thing to avoid should be a situation, when one event triggers another event, which, in turn, triggers first event again. You can run in infinite event chain here. This might happen when same class has the both subscriber and producer methods. If I have such classes, I try to keep those methods as independent as possible.
And of course I always use Android components' lifecycle to register and unregister publishers and subscribers dynamically. I start with onResume() and onPause() methods and, if needed, I'm going up to onStart() or even onCreate().