In my Android app I'm using the interval() operator to schedule multiple periodic jobs (which may run simultaneously):
public class Job {
...
public void start(Runnable runnable, Scheduler scheduler) {
Observable
.interval(this.initialDelay, this.interval, this.timeUnit)
.observeOn(scheduler)
.subscribe(t -> runnable.run());
}
...
}
My questions is:
Why does it use the computation() as default scheduler for the interval() operator?
obviously I can use the overloaded method and send different scheduler but I'm not sure how it may affect the performances or anything else by changing the scheduler.
Related
I have a behavior subject that will be DI. I then have different interfaces, that subscribe to that object. Below is a super simple one I am writing so that I can mostly restrict access to the subjects onNext() function. I am not able to figure out how to write a test for this in jUnit. This is RXjava2. I see a lot of blog posts that talk about tests Observers, testScheduler and so on, but none of them seem to block till a RX observable receives the next element.. My abstraction is not helping so I cant play with test observers and test observables, but is a requirement.
fun subscribe(subscribeThread: Scheduler, observeThread: Scheduler, next: Consumer<Location>, throwable: Consumer<Throwable>): Disposable {
return publishSubject
.subscribeOn(subscribeThread)
.observeOn(observeThread)
.subscribe(next, throwable)
}
I have my tests..
private var consumerResult: Consumer<Val> = Consumer { count++ }
#Test
fun `dispose custom and receive updates`() {
var disposable = myObserver.subscribe(testScheduler, testScheduler, consumerResult, consumerThrowable)
assertNotNull(disposable)
assertEquals(0, count)
subject.onNext(mockVal)
assertEquals(1, count) // FAILS
}
Which yes I expect it to fail as this is an async call. However I am not able to figure out how to write this so I can test my code.. Note this is the first step in a much larger complicated test
Without TestObserver I don't believe you'll be able to accomplish this. My recommendation would be to leverage the #VisibleForTesting annotation and write methods for passing an Observer to your Subject.
As an aside, I'm not sure I'm clear on how your approach succeeds in restricting access as you still allow for a Consumer to be passed into the subscription.
Can anyone please help me to explain which scheduler are running below code?
Completable.complete()
.subscribeOn(http://Schedulers.io ())
.observeOn(AndroidSchedulers.mainThread())
.delay(5000, TimeUnit.MILLISECONDS)
.doOnComplete(() -> liveDataState.postValue(""))
.subscribe()
My question is which schedulers are delay(), doOnComplete() and subscribe() are using io or mainThread?
After digging into RxJava threading last two days found the rule of thumbs for handling RxJava Threading/Scheduling:
observeOn works only downstream operator
subscribeOn works for both downstream and upstream operator
Consecutive/Multiple subscribeOn do not change the thread
Consequent observeOn do change the thread for downstream oerator
Unlike with subscribeOn(), we can use observeOn() multiple times for
seamless thread switching
Operator like delay(), interval() have default scheduler and can change the downstream scheduler as well
So, for my case:
Completable.complete() // IO scheduler based on subscribeOn scheduler
.subscribeOn(http://Schedulers.io ())
.observeOn(AndroidSchedulers.mainThread())
.delay(5000, TimeUnit.MILLISECONDS) // Default Computation scheduler
.doOnComplete(() -> liveDataState.postValue("")) // Computation scheduler by delay scheduler
.subscribe() // Computation scheduler by delay as well
Also, you can look into the marble diagram for more understanding:
Hi I'm using RxJava for my disk storage get and set operations. Basically I have a method like this:
public Observable<String> getStorageItem(String id, String type) {
return Observable.defer(new Func0<Observable<String>>() {
// Run db operations to get storage item.
}
}
The problem is that it's possible this method getStorageItem(...) gets subscribed to multiple times in a row. And the DB operations within the observable cannot run concurrently. What's my best option here? Should I manually create some sort've queue? Or does RxJava have some kind of tool that allows me to block the operation until a previous one is complete?
You can use a subscribeOn with a single-threaded scheduler created from an ExecutorService to make sure there's only one DB operation in progress:
ExecutorService exec = Schedulers.newSingleThreadExecutor();
Scheduler s = Schedulers.from(exec);
public Observable<String> getStorageItem(String id, String type) {
return Observable.fromCallable(() -> {
// Do DB operations
});
}
getStorageItem("1", "2").subscribeOn(s).subscribe(...);
getStorageItem("2", "4").subscribeOn(s).subscribe(...);
getStorageItem("3", "6").subscribeOn(s).subscribe(...);
But note that by moving the computation off the caller's thread, it may execute any time. If you need to wait for it individually (because the getStorageItem is already called on some thread), you can apply toBlocking() after subscribeOn.
I used RxJava in android with Retrofit 2 and I have invoked subscribeOn(Schedulers.io()) android observeOn(AndroidSchedulers.mainThread()) global before subscribe().
However, sometime I would like to call subscribeOn(Schedulers.immediate()) android observeOn(Schedulers.immediate()) to override the Schedulers set before to get synchronized process. But I found it doesn't work, android works would be still processed on io() thread, android result processed by mainThread().
Why?
That's just the way RxJava works.
Take a look at this video tutorial, starting at the 12:50 mark. So given the example in the video:
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.subscribe(System.out::println);
What happens is that subscribeOn() nests all calls. In this case subscribeOn(Schedulers.io()) is spawned first and subscribes everything above it on the io thread. But then subscribeOn(Schedulers.newThread()) is spawned next and it takes priority (since it was called last) to subscribe everything on it instead. There is no building a chain of threads. In this example, you are essentially spawning the io thread for no good reason.
To better handle the subscribeOn() and observeOn() methods, I suggest you take a look at this post from the same author of the video. What he is proposing is to use a Transformer to wrap the call to these methods:
Transformer is actually just Func1<Observable<T>, Observable<R>>. In
other words: feed it an Observable of one type and it'll return an
Observable of another. That's exactly the same as calling a series of
operators inline.
This way, you can have a method like so:
<T> Transformer<T, T> applySchedulers() {
return observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
Or, if you want to reuse your transformers, you can have the following setup:
final Transformer schedulersTransformer =
observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
#SuppressWarnings("unchecked")
<T> Transformer<T, T> applySchedulers() {
return (Transformer<T, T>) schedulersTransformer;
}
Then the above example would look like:
Observable.just(1, 2, 3)
.compose(applySchedulers())
.subscribe(System.out::println);
Hope that helps.
There is conflicting information about when and whether to use subscribeOn with Retrofit.
Here is an answer saying to not use subscribeOn.
Here is an answer seeming to imply that subscribeOn has no good default set.
Here is example code using subscribeOn.
So, once for for all, when should I use subscribeOn and with what thread? What are the possible ramifications of using or not using subscribeOn?
apiService.issueRequest()
// Is this useful? Required? Bad practice?
.subscribeOn(Schedulers.io())
// Do actions on main thread
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Response>() {
#Override public void call(Response response) {
handleResponse(response);
});
In the current version of Retrofit (1.9.0), Retrofit use his own executor to perform the http call and don't use the executor backed by the schedulers given by the subscribeOn method.
In your case, the scheduler will be used only to execute the code that will add your http call to the executor used by retrofit. (So it's a bit useless...)
BUT, regarding the actual code from Retrofit on Github, retrofit stop to use his executor, so it may be possible to used a RxJava scheduler instead.