How to Throw an Exception in OnNext using RxJava/RxAndroid - java

I am using Retrofit for the network call in my android app. Now if the response if something wrong (maybe wrong data), I do not want the onComplete to be executed. Please see the code snippet,
restClient.getService().getProjectDetail(projectId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<List<Project>>() {
#Override
public void onNext(List<Project> value) {
/*Something wrong in the data and I would like to execute onError*/
}
#Override
public void onError(Throwable e) {
handleError(e, 0, "");
hideProgressDialog();
}
#Override
public void onComplete() {
hideProgressDialog();
}
});
Thanks in advance.

Since your end-consumer can crash, the straightforward way is to catch that exception and delegate to onError:
.subscribeWith(new DisposableObserver<List<Project>>() {
#Override
public void onNext(List<Project> value) {
try {
// something that can crash
} catch (Throwable ex) {
// tell the upstream we can't accept any more data
dispose();
// do the error handling
onError(ex);
}
}
#Override
public void onError(Throwable e) {
handleError(e, 0, "");
hideProgressDialog();
}
#Override
public void onComplete() {
hideProgressDialog();
}
});
On a side note, RxJava does pretty much this in its own operators when dealing with potentially failing user functions: try-catch, cancel the source and signal through onError.

You can use flatMap. ex:
restClient.getService().getProjectDetail(projectId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<Integer, Observable<List<Project>>>() {
#Override
public Observable<List<Project>> apply(List<Project> x) {
if(validate(x)){
return Observable.error(new Exception("Response is invalid"));
}else {
return Observable.just(x);
}
}
public boolean validate(List<Project> x){
return x.size()==0;
}
})
.subscribeWith(new DisposableObserver<List<Project>>() {
#Override
public void onNext(List<Project> value) {
/*Something wrong in the data and I would like to execute onError*/
}
#Override
public void onError(Throwable e) {
handleError(e, 0, "");
hideProgressDialog();
}
#Override
public void onComplete() {
hideProgressDialog();
}
});
example other:
Observable.just(1)
.flatMap(new Function<Integer, Observable<Integer>>() {
#Override
public Observable<Integer> apply(Integer x) {
if(validate(x)){
return Observable.error(new Exception("Response is invalid"));
}else {
return Observable.just(x);
}
}
public boolean validate(Integer x){
return x==1;
}
})
.subscribe(new Observer<Integer>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onComplete() {
}
#Override
public void onError(Throwable e) {
Log.e("ERROR", e.getMessage());
}
#Override
public void onNext(Integer integer) {
Log.d("flatMap", "onNext: " + integer.toString());
}
});

You are questioning the basic behaviour of rx-java. if you want call hideProgressDialog only once. you should delete that from onError. the sequence must destroy after problem.
but if you want to get other items in onNext and avoid onError you can use this method on your observable chain:onErrorResumeNext
restClient.getService().getProjectDetail(projectId).onErrorResumeNext(/*Func1*/)
consider this method will emit List<Project> in onNext instead of onError. and onComplete would not call
as long as you use retrofit the onNext only will invoke one times. so the better solution is the first one

Related

Using backpressure in observables of cold type?

Since in Hot Observable , we must use backpressure strategy to prevent from crash but why we use backpressure for example in the following examples which are Cold type:
Example 1
// If we do not use backpressure, the program will crash
Flowable.interval(1, TimeUnit.MILLISECONDS, Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
#Override
public void accept(Long aLong) throws Exception {
// do smth
}
});
Example 2
Flowable.range(0, 1000000)
.onBackpressureBuffer()
.observeOn(Schedulers.computation())
.subscribe(new FlowableSubscriber<Integer>() {
#Override
public void onSubscribe(Subscription s) {
}
#Override
public void onNext(Integer integer) {
Log.d(TAG, "onNext: " + integer);
}
#Override
public void onError(Throwable t) {
Log.e(TAG, "onError: ", t);
}
#Override
public void onComplete() {
}
});

Calling dispose() when passing a subscriber that overrides onSubscribe

I am new to RxJava and if I understand correctly the Observer is passed the Disposable on the onSubscribe so it can manually stop the processing if the dispose() has already been called.
I created the following code:
#NonNull Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
private Disposable d;
#Override
public void onSubscribe(#NonNull Disposable d) {
this.d = d;
}
#Override
public void onNext(#NonNull Long aLong) {
if(!d.isDisposed()) {
System.out.println("Number onNext = " + aLong);
}
}
#Override
public void onError(#NonNull Throwable e) {
}
#Override
public void onComplete() {
System.out.println("completed");
}
});
but I can't figure out how to call dispose() for that subscription. subscribe with passing Observer as an argument returns void and subscribeWith does not accept my Observer without compile errors.
How is this supposed to work? What am I misunderstanding here?
The JavaDocs of Observable has a straightforward example:
Disposable d = Observable.just("Hello world!")
.delay(1, TimeUnit.SECONDS)
.subscribeWith(new DisposableObserver<String>() {
#Override public void onStart() {
System.out.println("Start!");
}
#Override public void onNext(String t) {
System.out.println(t);
}
#Override public void onError(Throwable t) {
t.printStackTrace();
}
#Override public void onComplete() {
System.out.println("Done!");
}
});
Thread.sleep(500);
// the sequence can now be disposed via dispose()
d.dispose();
Edit
The following examples are ways to get the Disposable out of the onSubscribe method but are generally not recommended:
// field in the owner class
Disposable disposable;
public void doReactive() {
Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
disposable = d;
}
// ...
});
}
public void cleanup() {
if (disposable != null) {
disposable.dispose();
disposable = null;
}
}
or
SerialDisposable sd = new SerialDisposable();
Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new Observer<Long>() {
#Override
public void onSubscribe(#NonNull Disposable d) {
sd.set(d);
}
// ...
});
// ...
sd.dispose();
You can use the DisposableObserver which can be easily disposed when you are done observing.
#NonNull Observable<Long> src = Observable.interval(1, TimeUnit.SECONDS);
src.subscribe(new DisposableObserver<Long>() {
#Override
public void onNext(#NotNull Long aLong) {
//Do anything you want to do..
dispose();
}
#Override
public void onError(#NotNull Throwable e) {
//Handle the errors here..
dispose();
}
#Override
public void onComplete() {
dispose();
}
});
You can also use CompositeDisposable to dispose many observers at one time, For more details check this out.
https://www.tutorialspoint.com/rxjava/rxjava_compositedisposable.htm

RxJava OnNext only works with the mainThread

When I switch from running the observeOn on the Main thread to a newThread, the onNext only runs once.
That only way I can get it to work is to keep it on the Main thread, but then I get that it does too much work on the Main Thread.
Without the setErrorHandler it just crashes (Also, can I use doOnError instead of RxJavaPlugins?)
PS. It works on the emulator fine, but it's on the physical device that the issue comes up.
public void updatePie() {
RxJavaPlugins.setErrorHandler(Functions.<Throwable>emptyConsumer());
Observable<Long> intervalObservable = Observable
.interval(1, TimeUnit.SECONDS)
//.doOnError(Functions.<Throwable>emptyConsumer())
.subscribeOn(Schedulers.io())
.takeWhile(new Predicate<Long>() {
#Override
public boolean test(Long aLong) throws Exception {
if (isMyServiceRunning(MyService.class) == false) {
RxB = false;
}
return RxB;
}
})
.observeOn(Schedulers.newThread());
intervalObservable.subscribe(new io.reactivex.Observer<Long>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Long aLong) {
triple = mService.Time;
entries.set(0, new PieEntry(mService.Time, "kronk"));
entries.set(1, new PieEntry(mService.Time2, "notre dame"));
pie_chart.notifyDataSetChanged();
pie_chart.invalidate();
}
#Override
public void onError(Throwable e) {
Log.d(TAG, "Pie Update " + e.toString());
}
#Override
public void onComplete() {
Log.d(TAG, "Pie Update completed");
}
});
}

Retrofit 2 Observable in RxJaxa 1: How to convert to RxJava 2

I was using this code in Retrofit and Rx Java 1 to return an observable from a Retrofit call like this:
mCompositeSubscription.add(
ServiceFactory.createRetrofitService().setLike(mediaId,sessionMgr.getAuthToken())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ResponseBody>() {
#Override
public final void onCompleted( ) {}
#Override
public final void onError(Throwable e) {
userMessageHandler.showDialog(mParentActivity,mParentActivity.getString(R.string.error_setting_data_title),
mParentActivity.getString(R.string.error_set_like_msg) + e.getMessage(),0);
}
#Override
public void onNext(ResponseBody response) { }
})
);
I can't figure out how to convert it to RX Java 2. I have come up with this but not sure it is right:
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new DisposableObserver<User>(){
#Override
public void onNext(User user) {
authMgr.setUser(user);
}
#Override
public void onError(Throwable t) {
mProgressDlg.dismiss();
alertDlg.showIt(mResources.getString(R.string.err_register),
t.getMessage(), "",
"", mParentActivity, JAlertDialog.POSITIVE,null);
}
#Override
public void onComplete() { }
});
You should be able to use the RxJava2 adapter in retrofit. This will allow you to have your Retrofit API return RxJava2 types.
Here's a solid example: https://medium.com/3xplore/handling-api-calls-using-retrofit-2-and-rxjava-2-1871c891b6ae
I came up with this but I'm still testing...
mCompositeDisposable.add( ServiceFactory.createRetrofitService().registerNewUser(BuildConfig.CLIENT_KEY, data.email,
data.fname, data.lname, data.birthday,data.city,
data.state, mAvatarUrl, coords, Long.toString(mSessionId) ,
data.pwd, layerMgr.getNonce() )
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableObserver<User>(){
#Override
public void onNext(User user) {
}
#Override
public void onError(Throwable t) {
mProgressDlg.dismiss();
alertDlg.showIt(mResources.getString(R.string.err_register),
t.getMessage(), "",
"", mParentActivity, JAlertDialog.POSITIVE,null);
}
#Override
public void onComplete() { }
}));

How to connect two subscriptions in RXJava/Android

How can I bind two subscriptions like:
1) Retrofit&RX which converts JSON into list of strings shown in recyclerView.
restClient.getCatFacts()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<CatFactsResponse>() {
#Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "onError, " + e.getMessage());
}
#Override
public void onNext(CatFactsResponse catFactsResponse) {
catFactsList = catFactsResponse.getCatFacts();
}
});
2) And Jack Wharton's RxBinding library to react to changes made in EditText widget.
subscription = RxTextView
.textChangeEvents(editText)
.debounce(400, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.newThread())
.subscribe(new Observer<TextViewTextChangeEvent>() {
#Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "onError >> " + e.getMessage());
}
#Override
public void onNext(TextViewTextChangeEvent textViewTextChangeEvent) {
Log.i(TAG, textViewTextChangeEvent.text().toString());
}
});
to get list which is dynamically filtered using EditText. Am I supposed to use classes like Subject or sth? If yes, then how should it look like? Thanks for help :)
You should use flatMap operator
subscription = RxTextView
.textChangeEvents(editText)
.debounce(400, TimeUnit.MILLISECONDS)
.map(new Func1<TextViewTextChangeEvent, String>() {
#Override
public String call(TextViewTextChangeEvent textViewTextChangeEvent) {
return textViewTextChangeEvent.text();
}
})
.flatMap(new Func1<String, Observable<CatFactsResponse>>() {
#Override
public Observable<CatFactsResponse> call(String text) {
return restClient.getCatFacts(text)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
})
.subscribe(...);

Categories

Resources