Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly handle onError inside RxJava (Android)?

I'm getting a list of installed apps on the device. It's a costly operation, so I'm using Rx for that:

    Observable<List> observable = Observable.create(subscriber -> {         List result = getUserApps();          subscriber.onNext(result);         subscriber.onError(new Throwable());         subscriber.onCompleted();     });      observable             .map(s -> {                 ArrayList<String> list = new ArrayList<>();                 ArrayList<Application> applist = new ArrayList<>();                 for (Application p : (ArrayList<Application>) s) {                     list.add(p.getAppName());                     applist.add(p);                 }                 return applist;             })             .subscribeOn(Schedulers.newThread())             .observeOn(AndroidSchedulers.mainThread())             .doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage()))             .subscribe(s -> createListView(s, view)); 

However, my problem is with handling errors. Normally, user launches this screen, waits for apps to load, selects what is best and goes to next page. However, when user quickly changes the UI - app crashes with NullPointer.

Okay, so I implemented this onError. However it still doesn't work, and with above usecase it throws me this:

    04-15 18:12:42.530  22388-22388/pl.digitalvirgo.safemob E/AndroidRuntime﹕ FATAL EXCEPTION: main         java.lang.IllegalStateException: Exception thrown on Scheduler.Worker thread. Add `onError` handling.                 at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:52)                 at android.os.Handler.handleCallback(Handler.java:730)                 at android.os.Handler.dispatchMessage(Handler.java:92)                 at android.os.Looper.loop(Looper.java:176)                 at android.app.ActivityThread.main(ActivityThread.java:5419)                 at java.lang.reflect.Method.invokeNative(Native Method)                 at java.lang.reflect.Method.invoke(Method.java:525)                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)                 at dalvik.system.NativeStart.main(Native Method)          Caused by: rx.exceptions.OnErrorNotImplementedException                 at rx.Observable$31.onError(Observable.java:7134)                 at rx.observers.SafeSubscriber._onError(SafeSubscriber.java:154)                 at rx.observers.SafeSubscriber.onError(SafeSubscriber.java:111)                 at rx.internal.operators.OperatorDoOnEach$1.onError(OperatorDoOnEach.java:70)                 at rx.internal.operators.NotificationLite.accept(NotificationLite.java:147)                 at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.pollQueue(OperatorObserveOn.java:177)                 at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.access$000(OperatorObserveOn.java:65)                 at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber$2.call(OperatorObserveOn.java:153)                 at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)                 at android.os.Handler.handleCallback(Handler.java:730)                 at android.os.Handler.dispatchMessage(Handler.java:92)                 at android.os.Looper.loop(Looper.java:176)                 at android.app.ActivityThread.main(ActivityThread.java:5419)                 at java.lang.reflect.Method.invokeNative(Native Method)                 at java.lang.reflect.Method.invoke(Method.java:525)                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)                 at dalvik.system.NativeStart.main(Native Method)          Caused by: java.lang.Throwable                 at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment.lambda$getAppList$25(ApplicationsFragment.java:267)                 at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment.access$lambda$2(ApplicationsFragment.java)                 at pl.digitalvirgo.safemob.fragments.wizard.ApplicationsFragment$$Lambda$3.call(Unknown Source)                 at rx.Observable$1.call(Observable.java:145)                 at rx.Observable$1.call(Observable.java:137)                 at rx.Observable.unsafeSubscribe(Observable.java:7304)                 at rx.internal.operators.OperatorSubscribeOn$1$1.call(OperatorSubscribeOn.java:62)                 at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:47)                 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)                 at java.util.concurrent.FutureTask.run(FutureTask.java:234)                 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:153)                 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:267)                 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)                 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)                 at java.lang.Thread.run(Thread.java:841) 

How should I properly handle this problem?

like image 614
a_dzik Avatar asked Apr 15 '15 16:04

a_dzik


People also ask

How does Java handle Rx errors?

Here, in the above code we see as soon as we get an exception in map operator and then we directly goto onError and the onNext doesn't get called or even onComplete. So, to handle the error in cases like this we use different operators and it will not move to onError directly. Let us understand them one by one.

How do you throw an exception in RxJava?

subscribe( item -> { /* handle success */ }, error -> { /* handle failure */ } ); This works best if you throw the exception as early as possible, as then you can do retries, alternative responses etc. easily. Don't exceptions that extend RuntimeException when thrown crash as they are not handled by RxJava?

How does RxJava work internally?

RxJava is a Java VM implementation of ReactiveX a library for composing asynchronous and event-based programs by using observable sequences. The building blocks of RxJava are Observables and Subscribers. Observable is used for emitting items and Subscriber is used for consuming those items.

What is onNext in RxJava?

onNext(): This method is called when a new item is emitted from the Observable. onError(): This method is called when an error occurs and the emission of data is not successfully completed. onComplete(): This method is called when the Observable has successfully completed emitting all items.


1 Answers

.doOnError() is an operator, and is not as such a part of the Subscriber.

Therefore, having a .doOnError() does not count as an implemented onError().

About the question in one of the comments, of course it is possible to use lambdas.

In this case simply replace

.doOnError(throwable -> L.e(TAG, "Throwable " + throwable.getMessage())) .subscribe(s -> createListView(s, view)) 

with

.subscribe(s -> createListView(s, view),     throwable -> L.e(TAG, "Throwable " + throwable.getMessage())) 
like image 132
LukeJanyga Avatar answered Oct 02 '22 15:10

LukeJanyga