I have to schedule same observable repeatedly for N number of times with M seconds delay between each observable:
O1____1sec____O2____1sec____O3____1sec____O4(completed)
Notice no delay between start and ending observable,
Observable<Precious> result = <~> // hidden for brevity (it's just a long time consuming observable that can take suppose up to 10 seconds or more)
Observable.timer(M,TimeUnit.SECONDS).compose(x -> result).take(N).subscribe();
Problem Here is result observable that is doing expensive network calls, will it timout itself after timer expires , or we have to tell it to do so , if so how?
You can use the combination of concatMap to concat the observables, and Delay to delay the emission of every one
/**
* Another elegant solution it would be to create an observable with the list of items, and then use
* concatMap to pass all items from the first observable to the second, then this second observable
* can be created used delay operator afterwards.
*/
#Test
public void delayObservablesWithConcatMap() {
Observable.from(Arrays.asList(Observable.just(1), Observable.just(2),Observable.just(3)))
.concatMap(s -> s.delay(100, TimeUnit.MILLISECONDS))
.subscribe(n -> System.out.println(n + " just emitted..."),
e -> {
},
() -> System.out.println("Everybody emitt!"));
new TestSubscriber().awaitTerminalEvent(1000, TimeUnit.MILLISECONDS);
}
You can see more examples of delay here https://github.com/politrons/reactive/blob/master/src/test/java/rx/observables/utils/ObservableDelay.java
To space out items from obsevable source so that they're emitted every N seconds, use the following pattern:
source.zipWith(Observable.interval(1, TimeUnit.SECONDS), (src, dummy) -> src)
Caveat here is that if your source observable takes more time than the interval, then the items get queued up.
Now that I've re-read your question and clarifications, I think what you need is this:
Observable.interval(1, TimeUnit.SECONDS)
.switchMap(dummy -> result)
This will unsubscribe and resubscribe to the result observable every 1 second. It will only workif your result observable cancels network calls on unsubscription.
Related
I am using RxJava Interval Like this:
compositeDisposable.add(
Observable.interval(1, TimeUnit.SECONDS)
.flatMap(tick -> {
return Observable.just(doWork(tick));
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateUI, e -> {
disableIndicator();
FirebaseCrashlytics.getInstance().recordException(e);
})
);
public Status doWork(long tick) {
// Doing heavy task
// Here the Status is an Enum class
return output
}
public void updateUI(Status value) {
// Updates UI accordingly
}
Everything works as expected, but I have a concern. So my doWork() method is doing some heavy task in bg and I am updating the UI in updateUI() method based on the result produced by that method.I am calling the doWork() every second using RxJava Interval. Usually it takes less than a second to execute the doWork() method. So I was just wondering what happens if I have lots of data and the doWork() method takes more than one seconds to execute, lets say it takes 2 seconds.But the interval will keep calling the doWork() method every second. Since my previous execution will take another one second to complete what will I get as return value?
So the thing happens is something like this:
Suppose the method doWork takes longer than a second to execute the command, the next execution gets queued BUT NOT delayed.
Lets say in n th second the method does something expensive which takes 3 seconds to complete and will produce a result A. Since the method is being executed after 1 seconds, there will be another 3 execution which will be queued which will not take longer than a second to execute and produce and will generate result B,C,D.
After n+3 seconds you will get all four results at once. That will be A B C D
So If you are hoping to see the result A at n+3 second and B C D after 1 seconds too (Means you don't want to get all four values at once), You need to do something like this:
Observable.timer(1, TimeUnit.SECONDS)
.flatMap(tick -> {
return Observable.just(doWork());
})
.repeat()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(value -> printUI(value), throwable -> {})
)
I'm trying to add a delay in between each batch write and I managed to get it working by modifying this example but I'm not sure this is the correct way to achieve this?
rxBleConnection.createNewLongWriteBuilder()
.setCharacteristicUuid(characteristic)
.setBytes(data)
.setWriteOperationAckStrategy(booleanObservable -> {
return Observable.zip(
Observable.timer(delayInMillis, MILLISECONDS).repeat()
,booleanObservable, (callback0, aBoolean) -> aBoolean);
})
.build()
Your approach would delay next (sub)writes if Observable.timer().repeat() would emit after the booleanObservable. Unfortunately that would work only for the second (sub)write as after that .repeat() would start to emit very quickly as it does not resubscribe to the upstream Observable. From .repeat() Javadoc:
Returns an Observable that repeats the sequence of items emitted by the source ObservableSource indefinitely.
If you would use Observable.timer(delayInMillis, MILLISECONDS).repeatWhen(completions -> completions) or Observable.interval(delayInMillis, MILLISECONDS) then these would make writes happen not more frequent than delayInMillis, MILLISECONDS apart.
If you would like to give the peripheral delayInMillis, MILLISECONDS time before issuing next write then there seems to be a simpler approach:
rxBleConnection.createNewLongWriteBuilder()
.setCharacteristicUuid(characteristic)
.setBytes(data)
.setWriteOperationAckStrategy(booleanObservable -> booleanObservable.delay(delayInMillis, MILLISECONDS))
.build()
I have a rxjava observable chain with a set of operators. Let's say I have the source Observable (emitting items always every minute), operator B that performs a network request, and timeout operator. I want the timeout operator only take into account items emitted from the operator B, but ignore those emitted by the source Observable. What I want is to end the subscription if in one hore, no items have been emitted from the operator B, as the server is down, for example, and no results are emmited to the subscriber.
Example:
Observable.timer(1, TimeUnit.SECONDS)
.flatMap { performNetworkRequest() }
.timeout(1, TimeUnit.HOUR)
So my idea is to end this timer after one hour with no server responses. But timeout operator does not work that way, as it is reseted one the timer observable emmits a new item every minute.
This is what Doc says
The Timeout operator allows you to abort an Observable with an onError termination if that Observable fails to emit any items during a specified span of time.
-Here you are emitting item every minute so its not working like you want.
I want to achieve the following with RxJava and as I may not have enough knowledge in this area would like to have some help :)
I need to create a PublishSubject which would emit events with the following sequence:
Emit 1, 2, 3
Buffer 4 in subscribe's completion if a certain condition is not satisfied (may be a network connection for example or some other condition).
For 5, 6 ... buffer after 4 if the condition is not satisfied yet.
Repeat to emit 4 after some time when the condition is satisfied.
If trying to emit 5,6 and the condition is satisfied, then instead of buffering 5, 6 ... after 4, just emit 4 and then 5, 6, 7 , 8 ...
The last 2 points are necessary because the sequence of emitting is really important, which makes difficulties for me to achieve to this.
I hope I could describe what I want to achieve :)
Findings: After asking this question I've done some findings and achieved the following:
private Observable observable = publishSubject
.observeOn(Schedulers.io())
.map(Manager::callNew)
.doOnError(throwable -> Logger.e(throwable, "Error occurred"))
.retryWhen(throwableObservable -> throwableObservable
.zipWith(Observable.range(1, 10), (n, i) -> i)
.flatMap(retryCount -> {
long retrySeconds = (long) Math.pow(2, retryCount);
Logger.d("The call has been failed retrying in %s seconds. Retry count %s", retrySeconds, retryCount);
return Observable.timer(retrySeconds, TimeUnit.SECONDS)
.doOnNext(aLong -> {
C24Logger.d("Timer was completed. %s", aLong);
})
.doOnComplete(() -> Logger.d("Timer was completed."));
}));
The problem is here with PublishSubject. Because it already has emitted all the items, it emits only new ones for retryWhen. If I use ReplaySubject them it emits also the old completed items too for the new retryWhen re-subscribe, which I do not need anymore.
Is there a way to use the ReplaySubject to remove the completed items from the buffer?
You want to be able to turn buffering on and off, depending upon an external condition. Perhaps the simplest way to do it is use the buffer() operator to continually buffer items based on the condition.
(I have removed stuff from the observer chain)
private Observable observable = publishSubject
.publish( obs -> obs.buffer( obs.filter( v -> externalCondition( v ) ) ) )
.flatMapIterable( bufferedList -> bufferedList )
.subscribe( ... );
The publish() operator allows multiple observer chains to subscribe to the incoming observer chain. The buffer() operator monitors the observable that emits a value only when the external condition is true.
When the external condition is true, buffer() will emit a series of lists with only a single element. When the condition goes false, buffer() starts buffering up the results, and when the condition goes true again, all the buffered items are emitted as a list. The flatMapIterable() step will take each item out of the buffer and emit it separately.
I am playing around with RxAndroid. I have a List of Observables all of which are api requests (using Retrofit). I want to fire one of them every x seconds or milliseconds but then zip the responses together. I seems that once I subscribe to Observable.zip(requests, someFunction) all of them are fired off at once. Any tips?
Thanks!
EDIT: looks like adding delaySubscription to each request maybe the answer
You are looking for either delay() or delaySubscription().
delay() will delay the result of the Observable being published to the subscriber.
delaySubscription() will delay subscription to the Observable.
Observable.zip(someObservable.delaySubscription(100, TimeUnit.MILLISECONDS),
someOtherObservable.delaySubscription(200, TimeUnit.MILLISECONDS),
someThirdObservable.delaySubscription(300, TimeUnit.MILLISECONDS),
new Func3<Object, Object, Object, Void>() {
...
}).subscribe();
Also, it's posible to achieve a periodical sending effect by using the interval() operator.
Let's see a simple example. Imagine you have an array, numbers, whose values have to emitted each x time. You could create an Observable that emits them:
Observable<Integer> values = Observable.from(numbers);
And now, another Observable that emits each (for instance) 30 milliseconds:
Observable<Long> interval = Observable.interval(30, TimeUnit.MILLISECONDS);
So, through the zip() operator you could combine both to achieve the periodical emission of the values in your number array:
Observable.zip(values, interval, (arrayElement, aLong) -> arrayElement)
.subscribe(arrayElement -> doSomething(arrayElement));
I used it to get an animation effect for a progress indicator. I wrote a complete example project you can check in github.