Continue next Observable onError - android

I have sequence of tasks to be completed, if any of them throws exception would like to continue with next task.
But with this implementation, if first REST calls fail it throws onError in subscriber.
Wondering what is best operator to use or I need to call some other function to make it resume on exception.
private void logout() {
// Observable from Retrofit to make logout service call
requestLogout()
.doOnNext(o -> {
clearNotifications();
})
.doOnNext(o -> {
unregisterGcm();
})
.doOnNext(o -> {
clearLocalData();
})
.doOnNext(o -> {
// clear all jobs
mJobManager.clear();
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Object>() {
#Override
public void onCompleted() {
// no op
}
#Override
public void onError(Throwable e) {
mView.navigateToLogin();
}
#Override
public void onNext(Object o) {
mView.navigateToLogin();
}
});
}

If you just want to re-subscribe use Observable.retry():
.observeOn(AndroidSchedulers.mainThread())
.retry().subscribe(new Subscriber<Object>() {
// rest of code

So I found way to execute all the Observables even if one of them have error. But this does not preserve order.
I am still looking for way where order is preserved and on error it should continue to next observable.
Observable.mergeDelayError(requestLogout(),
clearNotifications(),
unregisterGcm(),
clearLocalData(),
clearJobs())
.first()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Object>() {
#Override
public void onCompleted() {
// no op
}
#Override
public void onError(Throwable e) {
mView.navigateToLogin();
}
#Override
public void onNext(Object o) {
mView.navigateToLogin();
}
}
);

Related

How to set TimeOut for complete Observer in RXjava - Android?

I have many request merged in Observable, and I need a Timeout Not for every emission but for complete observable in RXjava. Is it Possible??
Observable
.merge(listOfObservables).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<Response>() {
#Override
public void onNext(#io.reactivex.annotations.NonNull Response response) {
}
#Override
public void onError(#io.reactivex.annotations.NonNull Throwable e) {
}
#Override
public void onComplete() {
}
});
You could use takeUntil with a delayed error:
Observable
.merge(listOfObservables)
.subscribeOn(Schedulers.io())
.takeUntil(Observable.error(new TimeoutException()).delay(5, TimeUnit.MINUTES, true))
.observeOn(AndroidSchedulers.mainThread())

how to call onComplete() used with interval() in rxjava

I'm new with rxjava.
implementation "io.reactivex.rxjava2:rxjava:2.2.8"
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
I'm working with interval(),
I don't know how to show View in onComplete() of rxjava without block UI Thread.
Or call onComplete() from onNext() in below codes :
Observable
.interval(0, 5, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(aLong -> {
Log.d("", "onNext()");
}, Throwable::printStackTrace, () -> {
Log.d("", "onComplete()");
Log.d("", "SHOW POP UP");
showView();
});
People who know,
Please tell me,
Thank you,
Following code may work.
Observable
.interval(0, 5, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Long>() {
Disposable d;
#Override
public void onSubscribe(#NonNull Disposable d) {
this.d = d;
}
#Override
public void onNext(#NonNull Long aLong) {
if(!d.isDisposed()) {
this.onComplete(); // this will call onComplete()
d.dispose();
}
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
showView();
}
});

Network call with RXJava and Retrofit correct implementation - Android

I want to make a simple api call to user endpoint(register a new user) and get auth token with the response. Can anyone explain the difference between this two network calls and what implementation is the correct one in my case?
private void registerProcess(User user) {
mSubscriptions.add(Network.getRetrofit().getUserToken(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Response<TokenResponse>>() {
#Override
public void call(Response<TokenResponse> tokenResponse) {
if (tokenResponse.code() == 200) {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Registration success!");
} else {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Registration failed");
}
}
}));
}
private void registerProcess(User user) {
Network.getRetrofit().getUserToken(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response<TokenResponse>>() {
#Override
public void onCompleted() {
/// what to do here???
}
#Override
public void onError(Throwable e) {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Registration failed");
}
#Override
public void onNext(Response<TokenResponse> tokenResponse) {
if (tokenResponse.code() == 200) {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Registration success!");
}
}
});
}
The first case:
there is no onError callback handling, hence, for example, IOException will crash your app.
The second:
subscription is not stored anywhere (unlike the first case), so it will leak if it's still running and not unsubscribed on activity's onDestroy callback for example.
onNext handles only the successful response, so if there is HTTP code different from 200 nothing will happen.
The correct implementation is the fusion of these two snippets:
private void registerProcess(User user) {
mSubscriptions.add(Network.getRetrofit().getUserToken(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Response<TokenResponse>>() {
#Override
public void onCompleted() {
// you might do nothing here
}
#Override
public void onError(Throwable e) {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Error!");
}
#Override
public void onNext(Response<TokenResponse> tokenResponse) {
if (tokenResponse.code() == 200) {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Registration success!");
} else {
mProgressbar.setVisibility(View.GONE);
showSnackBarMessage("Registration failed");
}
}
});
}
Don't forget to call mSubscriptions.clear() when activity (or fragment) is destroyed, to unsubscribe from all stored subscriptions.
P.S. You could utilize doOnSubscribe and doAfterTerminate operators, to set initial and terminal view states accordingly. For example to avoid multiple calls to mProgressbar.setVisibility(View.GONE):
mSubscriptions.add(Network.getRetrofit().getUserToken(user)
.doOnSubscribe(() -> mProgressbar.setVisibility(View.VISIBLE))
.doAfterterminate(() -> mProgressbar.setVisibility(View.GONE))
...

onNext() onError() callbacks not executing on second subscribtion android

I've an Observable something like this:
#GET("endpoint")
Observable<Something> getSomething();
and Subscriber like this
Subscriber<Something> somethingSubscriber = new Subscriber<Something>() {
public void onCompleted() {
}
public void onError(Throwable e) {
//handle exceptions
}
public void onNext() {
//do something
}
In my OnClickListener associated with a button, i make a subscription
getSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(somethingSubscriber);
If i don't have an internet connection, onError is called and i do some exception handling. when I press the button again (assume i want to retry), the callback methods do not get called.
I want that onNext / onError callbacks get called everytime I press the button.
There is extention for RxJava. It has a lot of "cool tools", but for handling retrofit errors you can use ResponseOrError class.
So in you case it would looks like:
final PublishSubject<Object> clickSubject = PublishSubject.create();
final Observable<ResponseOrError<Something>> responseOrErrorObservable = clickSubject
.flatMap(new Func1<Object, Observable<ResponseOrError<Something>>>() {
#Override
public Observable<ResponseOrError<Something>> call(Object o) {
return getSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.compose(ResponseOrError.<Something>toResponseOrErrorObservable());
}
})
.replay(1)
.refCount();
final Observable<Throwable> error = responseOrErrorObservable
.compose(ResponseOrError.<Something>onlyError())
.subscribe(new Action1<Segment>() {
#Override
public void call(Throwable throwable) {
// what to do on error, some toast or what ever yu need
}
});
final Observable<UserInfoResponse> success = responseOrErrorObservable
.compose(ResponseOrError.<Something>onlySuccess())
.subscribe(new Action1<Something>() {
#Override
public void call(Something some) {
// code what to do on success
}
});
And now, into onClick you just need to put clickSubject.onNext(null)
.replay(1).refCount(); needed because there are 2 Observables that uses responseOrErrorObservable, so without it retrofit request will "happens" two times.
You are reusing the same Subscriber. Once you get the onError or a result (so it completes) the subscriber is unsubscribed. Try to pass every time a new subscriber.
use this code
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getSomething()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Something>() {
#Override
public void call(Something something) {
//do something
}
},
new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
//handle exceptions
}
},
new Action0() {
#Override
public void call() {
}
});
}
});
Addition
or
replace this
Subscriber<Something> somethingSubscriber = new Subscriber<Something>() {
public void onCompleted() {
}
public void onError(Throwable e) {
//handle exceptions
}
public void onNext() {
//do something
}
};
to
Subscriber<String> somethingSubscriber = new Subscriber<String>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(String s) {
}
};
In my Case onNext() and onError() methods are not getting called because of my model class wrong parsing, I was taking a double object as Integer so NumberFormatException was thrown and nothing was happening after getting the result from retrofit.

Combining two different observables

Have the following snippet:
Log.d("#######", Thread.currentThread().getName());
RxSearchView.queryTextChangeEvents(searchView)
.debounce(400, TimeUnit.MILLISECONDS,Schedulers.newThread())
.flatMap(new Func1<SearchViewQueryTextEvent, Observable<GifsData>>() {
#Override
public Observable<GifsData> call(SearchViewQueryTextEvent txtChangeEvt) {
return RestWebClient.get().getSearchedGifs(txtChangeEvt.queryText().toString(),"dcJmzC");
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GifsData>() {
#Override
public void onCompleted() {
Log.d("#######","onCompleted searchGifs");
}
#Override
public void onError(Throwable e) {
Log.d("#######",e.toString());
}
#Override
public void onNext(GifsData gifsData) {
mainFragmentPresenterInterface.displaySearchedGifsList(gifsData);
}
});
}
No matter what i try i keep getting the following error:
java.lang.IllegalStateException: Must be called from the main thread. Was: Thread[RxNewThreadScheduler-2,5,main]
Probably have spend close to an hour on this..Haven't been able to figure out what is the issue. Even tried matching my snippet to the following link:
Combine RxTextView Observable and Retrofit Observable
No luck. Can someone point out what is wrong here?
Thanks.
Reason of error: You are subscribing result on background thread and you are accessing View in stream on background thread. Here I have invoked RestWebClient.get().getSearchedGifs(txtChangeEvt.queryText().toString(),"dcJmzC").subscribeOn(Schedulers.newThread());on background scheduler .Please try this it will work for you:
RxSearchView.queryTextChangeEvents(mSearchView)
.debounce(400, TimeUnit.MILLISECONDS)
.flatMap(new Func1<SearchViewQueryTextEvent, Observable<String>>() {
#Override
public Observable<String> call(SearchViewQueryTextEvent txtChangeEvt) {
return Observable.just(txtChangeEvt.queryText().toString()).subscribeOn(AndroidSchedulers.mainThread());
}
})
.flatMap(new Func1<GifsData, Observable<String>>() {
#Override
public Observable<GifsData> call(String txtChangeEvt) {
return RestWebClient.get().getSearchedGifs(txtChangeEvt,"dcJmzC").subscribeOn(Schedulers.newThread());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GifsData>() {
#Override
public void onCompleted() {
Log.d("#######","onCompleted searchGifs");
}
#Override
public void onError(Throwable e) {
Log.d("#######",e.toString());
}
#Override
public void onNext(GifsData gifsData) {
Log.d("#######", gifsData);
}
});
Let me know if it helps
Operator debounce by default uses computation scheduler, you need to change it to main thread (because you work with UI only on main).
Next thing is to schedule network request to be executed on io scheduler.
(we are using only one subscribeOn now).
And again observing results on main thread to inreact with UI.
RxSearchView.queryTextChangeEvents(searchView)
.debounce(400, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
.flatMap(new Func1<SearchViewQueryTextEvent, Observable<GifsData>>() {
#Override
public Observable<GifsData> call(SearchViewQueryTextEvent txtChangeEvt) {
return RestWebClient.get()
.getSearchedGifs(txtChangeEvt.queryText().toString(),"dcJmzC")
.subscribeOn(Schedulers.io());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<GifsData>() {
#Override
public void onCompleted() {
Log.d("#######","onCompleted searchGifs");
}
#Override
public void onError(Throwable e) {
Log.d("#######",e.toString());
}
#Override
public void onNext(GifsData gifsData) {
mainFragmentPresenterInterface.displaySearchedGifsList(gifsData);
}
});

Categories

Resources