What's the usage of the observable emitted by retrywhen() in rxjava2? - java

I know that if the Observable emits a piece of data, it resubscribes, and if the Observable emits an onError notification, it passes that notification to the observer and terminates. The problem is that if I emit a Obervable.just(1,2),but it won't be accept by the observer.So what's the usage of it?Dose it just tell it to resubscribes,and it's not important what data i emit?
Observable.just(1, "2", 3)
.cast(Integer.class)
.retryWhen(new Function<Observable<Throwable>, ObservableSource<Integer>>() {
#Override
public ObservableSource<Integer> apply(Observable<Throwable> throwableObservable) throws Exception {
return Observable.just(4,5);
}
})
.subscribe(new Consumer<Integer>() {
#Override
public void accept(Integer integer) throws Exception {
Log.i(TAG, "retryWhen重试数据"+integer);
}
});
and the log is
retryWhen重试数据1
retryWhen重试数据1
so Observable.just(4,5) is gone?

You can check out this example from the documentation to better understand how the retryWhen supposed to work (source: http://reactivex.io/RxJava/javadoc/io/reactivex/Observable.html#retryWhen-io.reactivex.functions.Function-):
Observable.create((ObservableEmitter<? super String> s) -> {
System.out.println("subscribing");
s.onError(new RuntimeException("always fails"));
}).retryWhen(attempts -> {
return attempts.zipWith(Observable.range(1, 3), (n, i) -> i).flatMap(i -> {
System.out.println("delay retry by " + i + " second(s)");
return Observable.timer(i, TimeUnit.SECONDS);
});
}).blockingForEach(System.out::println);
Output is:
subscribing
delay retry by 1 second(s)
subscribing
delay retry by 2 second(s)
subscribing
delay retry by 3 second(s)
subscribing

Related

Keep stream alive even after onComplete()

There are two issues which I am currently facing.
1) As soon as the line RetrofitProvider.getInstance().getCurrentWeather(.....) is called the network call is being done. How can it be deferred till the observer is connected to it.
2) Once weatherInfoPublisher.onComplete() is called, the next time I call onComplete on this object the new observer's onNext is not getting called.
public Observable<LinkedList<WeatherInfo>> getWeatherData(final String payload, final TempUnit tempUnit) {
PublishSubject weatherInfoPublisher = PublishSubject.create();
RetrofitProvider.getInstance().getCurrentWeather(payload + ",us", translateTempUnit(tempUnit))
.flatMap(new Function<String, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(String todayResponse) throws Exception {
Log.d(TAG, "Received today weather: " + todayResponse);
parseTodayData(todayResponse, weatherDataList);
return RetrofitProvider.getInstance().getForecastWeather(
payload + ",us", translateTempUnit(tempUnit), FORECAST_DAYS);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<String>() {
#Override
public void onNext(String futureResponse) {
Log.d(TAG, "Received future weather: " + futureResponse);
parseFutureData(futureResponse, weatherDataList);
weatherInfoPublisher.onNext(weatherDataList);
weatherInfoPublisher.onComplete();
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "The error is, " + e.getMessage());
}
#Override
public void onComplete() {
}
});
return weatherInfoPublisher;
}
This is a singleton class and the entire implementation has been provided in here in Github Link.
How can it be deferred till the observer is connected to it.
Do not subscribe to that observable in this method. Instead return that observable to the client. As soon as the observable is subscribed - a request would be performed.
the next time I call onComplete on this object the new observer's onNext is not getting called.
See reactive stream specs: if a stream completes - it can never be continued, that's a terminal event.

Using the Interval with Operators (RxJava)

I need to make a network request every 1/3 seconds and wait 3 seconds before onComplete method. How do I do that? my code below waits 3 seconds before emitting items, and it's not what I want.
disposable = Observable
.interval(0, 334, TimeUnit.MILLISECONDS)
.skipLast(9)
.take(postsCount + 9)
.subscribeWith(new DisposableObserver<Long>() {
#Override
public void onNext(#NonNull Long number) {
// Code in onNext method
}
#Override
public void onError(#NonNull Throwable e) {
// Code in onError method
}
#Override
public void onComplete() {
// Code in onComplete method
}
});
Don't sleep but use composition with the desired delay:
Observable.intervalRange(0, postCount, 0, 334, TimeUnit.MILLISECONDS)
.concatWith(Observable.empty().delay(3, TimeUnit.SECONDS))
... // react to each tick
Because if you want to skipLast 9 items, RxJava should collect 9 items first and then it can know which are 'last 9 items'. I think you can simply sleep 3000 ms onComplete.
Observable.interval(0, 334, TimeUnit.MILLISECONDS)
.take(postsCount)
.doOnComplete { Thread.sleep(3000) }
.doOnNext { println(it) }
.doOnComplete { println("completed") }
.blockingSubscribe()

RxJava 2 - Call Completable after another Completable

I'm a newbie in RxJava and faced an issue as follows:
I have two Completable objects to store some data. I'd like to trigger the first one and later on start the second one only after the first one has finished with success. The call to the second Completable should be blocked until the first one has finished with success. Also, if the first one has finished with error, the other one should be also skipped.
Looking through documentation and other SO questions it seems that concatWith or andThen should work for me. But in both manual test and unit test I can see that the second completable is triggered in parallel to the first one :/
First completable
public Completable doA() {
Log.d(TAG, "class call");
return db.countRows()
.doOnSuccess(integer -> {
Log.d(TAG, "found rows: "+integer);
})
.doOnError(Throwable::printStackTrace)
.flatMapCompletable(this::customAction);
}
private Completable customAction(final int count) {
Log.d(TAG, "count: "+count);
if (count > 0) {
Log.d(TAG, "no rows, skip");
return Completable.complete();
}
final User user = ...
return db.save(user); // return Completable
}
Second Completable
public Completable doB() {
Log.d(TAG, "call to B");
// ...
}
Attempt to invoke B after A
public Completable someMethod() {
Log.d(TAG, "someMethod");
return doA()
.andThen(doB());
// this also doesn't work
//.concatWith(doB());
}
The subscription
someMethod()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnComplete(() -> {
Log.d(TAG, "complete");
// ...
})
.doOnError(throwable -> {
Log.d("Main", "error "+throwable.getMessage());
// ...
})
.subscribe();
When I run my app and check logs I can see:
D/Some method: some method
D/DoA: class call
D/DoB: class call // <- why here?
D/DoA: found rows: 0
D/DoA: count: 0
Also the following unit test fails:
#Test
public void test() {
when(doa.doA()).thenReturn(Completable.error(new Exception("test")));
observe(); // subscription with TestObserver
verify(dob, never()).doB(); // fails with NeverWantedButInvoked
}
What am I missing?
Because you called doB(). Let me rewrite your flow:
public Completable someMethod() {
Log.d(TAG, "someMethod");
// doA() inlined
LOG.d("class call");
Completable a = ...
// doB() inlined
Log.d("class call");
Completable b = ...
return a.andThen(b);
}
You can use andThen() or concatWith() operator.
Returns a Completable that first runs this Completable and then the other completable.
andThen()
firstCompletable
.andThen(secondCompletable)
In general, this operator is a "replacement" for a flatMap on Completable:
Completable andThen(CompletableSource next)
<T> Maybe<T> andThen(MaybeSource<T> next)
<T> Observable<T> andThen(ObservableSource<T> next)
<T> Flowable<T> andThen(Publisher<T> next)
<T> Single<T> andThen(SingleSource<T> next)
concatWith:
firstCompletable
.concatWith(secondCompletable)

rxjava onStart event with delaySubscription

Observable.create(new Observable.OnSubscribe<Integer>() {
#Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onStart();
subscriber.onNext(1);
subscriber.onCompleted();
}
}).delaySubscription(5, TimeUnit.SECONDS).subscribe(new Subscriber<Integer>() {
#Override
public void onCompleted() {
Log.e("TAG", String.format("(%s) - onCompleted", System.currentTimeMillis()));
}
#Override
public void onError(Throwable e) {
Log.e("TAG", String.format("(%s) - onError", System.currentTimeMillis()), e);
}
#Override
public void onNext(Integer integer) {
Log.e("TAG", String.format("(%s) - onNext: %s", System.currentTimeMillis(), integer));
}
#Override
public void onStart() {
super.onStart();
Log.e("TAG", String.format("(%s) - onStart", System.currentTimeMillis()));
}
});
output:
(1485004553817) - onStart
(1485004558818) - onNext: 1
(1485004558819) - onCompleted
why onStart event not waiting to delaySubscription and calling soon ?
i want aware when call method called
Documentation says -
onStart -
This method is invoked when the Subscriber and Observable have been connected but the Observable has not yet begun to emit items or send notifications to the Subscriber.
delaySubscription:
Returns an Observable that delays the subscription to the source Observable by a given amount of time.
onNext is invoked only when the subscription is achieved. onStart is called the moment a connection is established. Thus, it works as expected according to the definition.
You can try commenting the code subscriber.onStart(); and execute the same again to notice that onStart is still called at the beginning. The intentional execution did not really invoke the said method because this was executed not on the real subscriber we created, but the one which was a result of delaySubscription (of type OnSubscribeDelaySubscription).
Below is a snippet which can probably help you achieve what you're looking for:
public static void main(String[] args) throws UnsupportedEncodingException, IOException {
Observable.timer(5, TimeUnit.SECONDS).flatMap(val -> {
System.out.println("Initialize");
return Observable.create(subscriber -> {
System.out.println("onsubscribe");
doMyAsyncStuff(subscriber);
});
}).subscribe(val -> System.out.println(val));
Observable.timer(10, TimeUnit.SECONDS).toBlocking().first();
}
We initialize a timer, once timer is executed, we perform some task in flatMap which should be the same as what you earlier did with onStart. Once that task is executed, we emit a Observable which emits all the elements that you could have consumed earlier with onNext calls.

How to make RxJava interval to perform action instantly

Hello I am making observable to ask my server about its online/offline status every 15 seconds:
public Observable<Response> repeatCheckServerStatus(int intervalSec, final String path) {
return Observable.interval(intervalSec, TimeUnit.SECONDS)
.flatMap(new Func1<Long, Observable<Response>>() {
#Override
public Observable<Response> call(Long aLong) {
return Observable.create(new Observable.OnSubscribe<Response>() {
#Override
public void call(Subscriber<? super Response> subscriber) {
try {
Response response = client.newCall(new Request.Builder()
.url(path + API_ACTION_CHECK_ONLINE_STATUS)
.header("Content-Type", "application/x-www-form-urlencoded")
.get()
.build()).execute();
subscriber.onNext(response);
subscriber.onCompleted();
if (!response.isSuccessful())
subscriber.onError(new Exception());
} catch (Exception e) {
subscriber.onError(e);
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
});
}
After I call this method, first execution of code will be after intervalSec time (15sec in my case). Looking at rxJava docummentation of interval method:
http://reactivex.io/documentation/operators/interval.html
This is how it should be.
Question: is there any way to execute code instantly and then repeat in intervals?
You can execute it immediately also like this:
Observable.interval(0, 1000, TimeUnit.MILLISECONDS).subscribe();
What you are looking for is startWith
Observable.interval(15, SECONDS).startWith(1);
This will get the updates from the interval, but emit one item immediately after subscribing.
you can use `
Observable.interval(1, TimeUnit.SECONDS).startWith(0)
`
It is duplicate value "0" in subscribe.

Categories

Resources