I am very new to RxAndroid and am still trying to navigate my way out of the errors that I am making.
Observable.just(RandomComputeManager.getChartData(0,"abcd",new Date()))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
System.out.println("RXANDROID"+ s.getFood());
Toast.makeText(getActivity(),"HELLO"+s.getFood(),Toast.LENGTH_LONG);
});
I have a heavy computation method here that I am trying to run on RxJava's Schedulers.computation() thread.(I do not know if only calling it in Observable.just is the right way). The method is supposed to throw an exception if it does not have data.
Class RandomComputeManager{
public static getPieChartData(int a,String b,Date c) throws CustomException {
if(haveData){
//All Okay
}
else{
throw new CustomException("No Data");
}
}
The build is failing with error
error: unreported exception CustomException; must be caught or declared to be thrown
I have tried adding an observer to the subscribe method thinking that it has a onError method but neither is that solving this issue nor am I able to fetch my data then due to some ambiguity in the return value of the called method(Don't know if it should be an observable or just the object I need).
Please suggest a way to handle this.
The subscriber function can take another argument of throwable.
Please do like this
Observable.just(RandomComputeManager.getChartData(0,"abcd",new Date()))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
System.out.println("RXANDROID"+ s.getFood());
Toast.makeText(getActivity(),"HELLO"+s.getFood(),Toast.LENGTH_LONG);
}, throwable ->{
});
Observable.fromCallable(RandomComputeManager.getChartData(0,"abcd",new Date()))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s -> {
System.out.println("RXANDROID"+ s.getFood());
Toast.makeText(getActivity(),"HELLO"+s.getFood(),Toast.LENGTH_LONG);
}, Throwable :: printStackTrace);
This did the trick. Thanks to Gautam Kumar and Raj Suvariya for your help. I found this detail from Exception handling in rxjava
just method accepts parameters that are resolved immediately, so you actually are about to run the computation at the very same line you create your Observable. Also, this is the reason that your exception is not caught, as the getChartData is not called within Observable on-subscribe function.
What you need here is to create the Observable passing a computation function, but you are trying to pass the computed result.
I am used to Kotlin, so sorry if I mess up Java lambdas here, but you should use fromCallable here, like so
Observable.fromCallable(
() -> RandomComputeManager.getChartData(0, "abcd", new Date())))
fromCallable accepts a function that will execute once you subscribe and will emit the function result.
Also, for your purpose it's better to use a Single, as you will have only one item emitted.
Single.fromCallable(
() -> RandomComputeManager.getChartData(0, "abcd", new Date())))
Also if your your CustomException is checked and you don't want to crash, you do have to add onError handling, like already suggested by others.
Related
Im new to rx and have some lines of code that confuse me:
Observable.just(1,2,3,4,5,6)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value ->
Log.i("TEST", "$value")
}
.dispose()
it will not log the result but when i comment out subscribeOn () and observeOn() or dispose() then it works perfectly, like this:
Observable.just(1,2,3,4,5,6)
.subscribe { value ->
Log.i("TEST", "$value")
}
.dispose()
or
Observable.just(1,2,3,4,5,6)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value ->
Log.i("TEST", "$value")
}
Can someone explain what happen inside this chain
When you write .subscribeOn(Schedulers.io()) this essentially means that Observable will operate on io thread, which will require a thread switch causing some delay.
by the time it happens you have already called the dispose() method which disposes the Observable hence you don't receive any output.
On the other hand if you remove
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
This means Observable will operate on the calling thread so no thread switch is required, hence you receive complete output before dispose() method call can be executed.
If you only remove dispose() then nothing is stopping the Observable from emitting its contents even though its executing on io
Observable.just(1,2,3,4,5,6) -> The Just operator converts an items into an Observable that emits these items.
subscribeOn() -> operator tells the source Observable which thread to emit and push items on all the way down to Observer
observeOn() -> it will switch and pass emissions using that Scheduler for the remaining (downstream) operations
subscribe() -> operator returns Disposable object. You should assign this object to variable or to CompositeDisposable object. All disposables should be dispose (using dispose() method) while your Activity or Fragment ends life to avoid memory leak.
More you can find here:
https://proandroiddev.com/understanding-rxjava-subscribeon-and-observeon-744b0c6a41ea
http://reactivex.io/documentation/operators.html#creating
You can also check Kotlin Coroutines as an alternative to RxJava
I am trying to call multiple network calls(5 in total) ,each is independent of the others. I know how to call network calls in chain with RxJava. But by calling in chain, if there is an error in calling 3rd or 4th network call, the rest of the calls will not be executed. So I want the rest of the network calls to continue to be executed even when the former calls failed. Is there a way to achieve the solution for this situation?
Yes, there is, you can use onErrorResumeNext. example of my code :
primaryMenuFetcher.getMenu()
.observeOn(uiScheduler)
.flatMap { menuItems ->
onView {
primaryMenu = menuItems
setPrimaryMenuList(primaryMenu)
}
return#flatMap model.getPromotions()
}
.onErrorResumeNext { return#onErrorResumeNext model.getPromotions() }
.observeOn(uiScheduler)
.doFinally { onView { hideProgressBar() } }
.subscribe({ fetchedLeagues ->
onView {
featuredLeagues = fetchedLeagues
showPopularLeagues()
setPopularLeaguesList(featuredLeagues)
}
}, {
showError()
})
There is also other Rx2 error handling options. Refer documentation
I think one of the best things here would be mergeDelayError. This will delay the errors until all observables completed or errored.
This would be one option:
Observable.mergeDelayError(
obs1.subscribeOn(Schedulers.io()),
obs2.subscribeOn(Schedulers.io()),
//...
)
.subscribe();
The subscribeOn is more to guarantee that the requests run in parallel. I don't know if the io scheduler is the most suitable in this scenario, but it has been working for me.
If the stream errors, you'll get a composite exception with each problem that occurred for each individual observable. If you need to check these individually you can look at this exception.
When I use retrofit with Single if error throw from doAfterSuccess observer onError not call and app crash(UndeliverableException) but when I create Single myself and throw an exception from a doAfterSuccess observer onError call.
Why doAfterSuccess behave two different way?.
The Single protocol is defined as follows: onSubscribe (onSuccess | onError)?. In words, if onSuccess is called, onError can't be called and vice versa. The doAfterSuccess can nowhere to go with respect to this protocol and to avoid losing possibly important exceptions, it is routed to the global error handler. The wiki has more detailed explanations about it.
If you find yourself wanting to invoke onError after an onSuccess, you are probably using the wrong type. The Observable protocol allows calling onError from whitin or after an onNext.
Alternatively, use try-catch in your unreliable onSuccess handler and call the same code as you'd call from onError.
Single.just(1)
.doAfterSuccess(v -> {
try {
process(v);
} catch (Throwable ex) {
reportError(ex);
}
})
.subscribe(v -> { /* ok */ }, e -> { reportError(e); });
AIM: Refresh an adapter when something changes, but only when the user has stopped scrolling the list.
I am trying to throw an error in doOnNext so that I can then wait and retry again. However, this isn't working. I can see that the exception is being thrown, but retryWhen doesn't seem to be doing anything.
What am I doing wrong here?
someObservable()
.observeOn(AndroidSchedulers.mainThread())
.debounce(650, TimeUnit.MILLISECONDS)
.doOnNext(o -> {
if (isListScrolling()) {
throw new IllegalStateException();
}
})
.retryWhen(errors -> errors.flatMap(error -> Observable.timer(100, TimeUnit.MILLISECONDS)))
.subscribe(o -> refreshListNow());
UPDATE:
someObservable is a Subject (Bus) that I'm observing UI events on.
See my comment below, as it seems retry() here won't work how one would expect (i.e. retry does not cause the source to automatically re-emit the last value, unless I was perhaps to use a BehaviorSubject - which isn't suitable here).
You didn't mention what value is emmited. So I'll just make it a string for this example. Checking the scrolling state inside doOnNext is too late, since they can not be propagated back to retryWhen. You can simply use flatMap to throw an error instead.
Observable.just("someValue")
.observeOn(AndroidSchedulers.mainThread())
.debounce(650, TimeUnit.MILLISECONDS)
.flatMap((Func1<String, Observable<?>>) s -> {
if (isListScrolling()) {
// Still scrolling, pass error so we can retry in the next step
return Observable.error(new Exception());
}
// Not scrolling, we can continue
return Observable.just("someValue");
})
.retry()
.subscribe(o -> refreshListNow());
I'm new to RxJava, often got confused by flatMap function. According to the doc, flatmap transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable
Can someone give a good use case for it? Why transform the original Observable into Observables (plural) then turn them into a single Observable.
Why don't you just use 'map'?
If you give an example in Android that's awesome, otherwise plain Java is good enough. Thanks
I see tag Android on your question. So, probably you should be familiar with Retrofit.
Let's image that you have 2 methods:
public interface FoxreyRestApi {
#POST("/signin")
Observable<SignInResponse> signin(#Body SignInRequest request);
#GET("/user")
Observable<User> getUser(String accessToken);
}
You want to get user data, but you need accessToken, which return is SignInResponse.
You can do this:
1). Create your RestAdapter.
2). Do queries one - after - another:
restAdapter.signin(request)
.flatMap(r -> restAdapter.getUser(r.getAccessToken()))
.subscribe(user -> {/*User your user*/});
Let's say you have an
Observable<Foo> fooObservable;
And you want to call another method which takes a Foo and emits an Observable<Bar>
Something like:
public Observable<Bar> getBars(Foo foo);
If you did:
fooObservable.map(foo -> getBars(foo));
You'd end up with an Observable<Observable<Bar>> because you've transformed your Foo -> Observable<Bar> which is probably not what you want.
Instead you can use flatMap which "flattens the observable":
Observable<Bar> barObservable = fooObservable.flatMap(foo -> getBars(foo));
Very often I use it to transform some of the UI events to observable background tasks:
ViewObservable.clicks(calculateBtn)
.flatMap(new Func1<OnClickEvent, Observable<Integer>>() {
#Override
public Observable<Integer> call(OnClickEvent onClickEvent) {
return observeBackgroundOperation()
.observeOn(AndroidSchedulers.mainThread())//interaction with UI must be performed on main thread
.doOnError(new Action1<Throwable>() {//handle error before it will be suppressed
#Override
public void call(Throwable throwable) {
progress.setVisibility(View.GONE);
calculateBtn.setEnabled(true);
Toast.makeText(IOCombineSampleActivity.this, R.string.mix_error_message, Toast.LENGTH_SHORT).show();
}
})
.onErrorResumeNext(Observable.<Integer>empty());//prevent observable from breaking
}
})
.subscribe(new Action1<Integer>() {...});
Because it's easy to define background operations using observable, I used flatMap to transform button click events to 'something done in background events' (for example network request finished with Retrofit) and then observe them.
Note, that observable in flatMap can emit single value, which is done in sample.
This way I have declaratively defined interaction between UI and background processes.
I handle errors with doOnError and then use onErrorResumeNext(Observable.<Integer>empty()) to prevent observable from terminating with onError. Because I use flatMap, my observable is not completed (while inner flatMap was) and is waiting for next click events.
Full sample of code you can find in my article.