RxJava Observable doOnNext vs subscribe() - java

I'm not quite understanding the difference between using an observable's doOnNext/doOnSubscribe/doOnComplete versus passing in an observer through the observable's subscribe function. These two seem to do the same thing to me. Can someone give me a use case where I would use one over the other?
Observable.interval(1, TimeUnit.SECONDS)
.take(30)
.map(v -> v + 1)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Long>() {
#Override
public void accept(Long aLong) throws Throwable {
// update UI
}
})
Observable.interval(1, TimeUnit.SECONDS)
.take(30)
.map(v -> v + 1)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
}
#Override
public void onNext(#NonNull Long aLong) {
// update ui
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
}
})

Related

How to wait for flowable onComplete?

In RxJava2, here is my code:
public void myMethod() {
Flowable.create(e->{
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation())
.observeOn(Schedulers.io())
.subscribe(new Subscriber<ContentsWithChannelVO>() {
#Override
public void onSubscribe(Subscription subscription) { // do sth. }
#Override
public void onNext(ContentsWithChannelVO contentAndChannel) { // do sth. }
#Override
public void onError(Throwable throwable) { // do sth. }
#Override
public void onComplete() { // do sth. }
});
doSomething();
}
Here is a synchronized problem.
I want to know how to let my method wait for the flowable onComplete, that is to say doSomething() will be called after the flowable onCompleted.
I have searched for it but it doesn't help.
You can use concat operator, but you need to wrap your method in another observable.
Concat waits to subscribe to each additional Observable that you pass
to it until the previous Observable completes.
You'd have to block the consumption of the flow for that (which is generally not recommended):
public void myMethod() {
Flowable.create(e -> {
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation(), false)
.blockingSubscribe(new Subscriber<ContentsWithChannelVO>() {
#Override
public void onSubscribe(Subscription subscription) { // do sth. }
#Override
public void onNext(ContentsWithChannelVO contentAndChannel) { // do sth. }
#Override
public void onError(Throwable throwable) { // do sth. }
#Override
public void onComplete() { // do sth. }
});
doSomething();
}
In this case, having observeOn is pointless. Note also you have to use subscribeOn() with false otherwise the flow livelocks.
If you don't want to execute doSomething if the source fails, use blockingForEach:
public void myMethod() {
Flowable.create(e -> {
// do sth.
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.computation(), false)
.blockingForEach(contentAndChannel -> { /* do sth. */ });
doSomething();
}

Observable merge() detect which observable is triggered

I'm creating a list of Observable using a list of values, foreach value a custom Observable. I run them all using merge, but I can't detect which one triggers onNext() or onError()
Like in the code below:
List<Observable<MyHttpRsObj>> observables = new ArrayList<>();
for (String param : paramsList) {
Observable<MyHttpRsObj> objObservable = MyRestClient.get().doHttpRequest(param);
observables.add(fileUploadObservable);
}
Observable<BaseRs> combinedObservables = Observable.merge(observables);
combinedObservables.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MyHttpRsObj>() {
#Override
public void onCompleted() {
//called only once when all Observables finished
}
#Override
public void onError(Throwable throwable) {
//how to know which Observable has error (which param)
}
#Override
public void onNext(MyHttpRsObj myHttpRsObj) {
//how to know which Observable has sccess (which param)
}
});
It is impossible to know which obsevable triggered the error since you merge all observables into single one.
your best bet is to use one observer for each observable. And a last one for merged Observable.
Like this:
List<Observable<MyHttpRsObj>> observables = new ArrayList<>();
for (String param : paramsList) {
//change to connectable Observable
ConnectableObservable<MyHttpRsObj> objObservable = MyRestClient.get()
.doHttpRequest(param)
.publish();
//don't forget to connect
observable.connect();
observables.add(fileUploadObservable);
//subscribe for each observable
objObservable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MyHttpRsObj>() {
#Override
public void onCompleted() {
//just partial completed
}
#Override
public void onError(Throwable throwable) {
//you can access param from here
}
#Override
public void onNext(MyHttpRsObj myHttpRsObj) {
//access onNext here
//you can access param from here
}
});
}
Observable<BaseRs> combinedObservables = Observable.merge(observables);
combinedObservables.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Subscriber<MyHttpRsObj>() {
#Override
public void onCompleted() {
//called only once when all Observables finished
}
#Override
public void onError(Throwable throwable) {
//don't handle error here
}
#Override
public void onNext(MyHttpRsObj myHttpRsObj) {
}
});
PS: use ConnectableObservable to avoid emitting twice

How to unsubscribe from the rxJava request

I have the following class, I want to return Subscription object or something else so I can cancel the request from where I have referenced subscribe() method , but subscribe(observer) returns void!
How can I do that?
public abstract class MainPresenter<T> {
protected <T> Disposable subscribe(Observable<T> observable, Observer<T> observer) {
observable.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
[New Update]
I used this way temporary, I am waiting for better solutions:
protected <T> DisposableMaybeObserver subscribe(final Maybe<T> observable,
final Observer<T> observer) {
return observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableMaybeObserver<T>() {
#Override
public void onSuccess(T t) {
observer.onNext(t);
}
#Override
public void onError(Throwable e) {
observer.onError(e);
}
#Override
public void onComplete() {
observer.onComplete();
}
});
}
[New Update 2]
[![Screenshot][https://i.stack.imgur.com/mioth.jpg]]
[New Update 3]
[]1
You should maybe use use subscribeWith :
private Disposable mDisposable;
public abstract class MainPresenter<T> {
protected Disposable subscribe(Observable<T> observable, DisposableObserver<T> observer) {
mDisposable = observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(observer);
return mDisposable;
}
Then when you need :
if (mDisposable != null && !mDisposable.isDisposed()) {
mDisposable.dispose();
}
Hope this helps.

Get values of an Array from an Observable

I have an Observable<MoviesResponse>. My MovieResponse class contains a getResults() methods returning a List<Result>. This Result class has a getTitle() methods returning a String. I want to call the getTitle() methods of all my Result objects to get all the titles of my movies.
I achieved this with the code below using a foreach loop but I think there is a better way to do this by chaining RxJava operators, I just can't figure it out...
Subscription :
Observable<MoviesResponse> moviesResponseObservable = apiService.getTopRatedMoviesObservable(API_KEY);
subscription = moviesResponseObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<MoviesResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(MoviesResponse moviesResponse) {
List<Result> results = moviesResponse.getResults();
for (Result r:results) {
Log.d(LOG_TAG,r.getTitle());
}
}
});
Interface :
public interface ApiService {
#GET("movie/top_rated")
Observable<MoviesResponse> getTopRatedMoviesObservable(#Query("api_key") String apiKey);
}
You can use a flatmap to transform your observable into an Observable<Result> and then use map to turn that into Observable<String>, which you can then subscribe to.
moviesReponseObservable
.subscribeOn(Schedulers.io())
.flatMapIterable(new Function<MoviesResponse, Iterable<Result>>() {
#Override
public Iterable<Result> apply(#NonNull MoviesResponse moviesResponse) throws Exception {
return moviesResponse.getResults();
}
})
.map(new Function<Result, String>() {
#Override
public String apply(#NonNull Result result) throws Exception {
return result.getTitle();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onNext(String s) {
Log.d("TAG", s);
}
/* ... */
});
I got the following error with #zsmb13 answer :
new Function : map (rx.functions.Func1) in
Observable cannot be applied to (anonymous
java.util.function.Function)reaso‌​n:
no instance(s) of type variable(s) R exist so that Function conforms to Func1
Anyway this answer was very helpul I just replaced Function with Func1 and used call method.
subscription = moviesResponseObservable
.subscribeOn(Schedulers.io())
.flatMapIterable(new Func1<MoviesResponse, Iterable<Result>>() {
#Override
public Iterable<Result> call(MoviesResponse moviesResponse) {
return moviesResponse.getResults();
}
})
.map(new Func1<Result, String>() {
#Override
public String call(Result result) {
return result.getTitle();
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
Log.d(LOG_TAG, s);
}
});

Get error and resubscribe

Is it possible to resubscribe an Observable and get the error?
The Observable<T> retry() method resubscribes the observable but it consumes the error.
final PublishSubject<Integer> observable = PublishSubject.create();
observable
.flatMap(new Func1<Integer, Observable<Integer>>() {
#Override
public Observable<Integer> call(final Integer integer) {
if (integer % 2 == 0) {
return Observable.just(integer);
} else {
return Observable.error(new Exception("int: " + integer));
}
}
})
.retry()
.subscribe(new Action1<Integer>() {
#Override
public void call(final Integer integer) {
Timber.i("integer: %d", integer);
}
},
new Action1<Throwable>() {
#Override
public void call(final Throwable throwable) {
Timber.e(throwable, "throwable");
}
},
new Action0() {
#Override
public void call() {
Timber.w("onCompleted");
}
});
Observable
.range(0, 10)
.delay(2, TimeUnit.MILLISECONDS)
.subscribe(new Action1<Integer>() {
#Override
public void call(final Integer integer) {
observable.onNext(integer);
}
},
new Action1<Throwable>() {
#Override
public void call(final Throwable throwable) {
observable.onError(throwable);
}
},
new Action0() {
#Override
public void call() {
observable.onCompleted();
}
});
The onError part of observable is never called because .retry() consumes the error.
What you're looking for is retryWhen(). This allows you to pass a Func1 which provides you with the Throwable, that means you can place your onError logic there instead.
This is a good article.

Categories

Resources