RuntimeException thrown and not caught in RxJava2 Single after it has been disposed

落爺英雄遲暮 提交于 2019-12-11 04:59:20

问题


A RuntimeException thrown inside an RxJava2 Single is not getting caught and is not getting sent to the Observer's onError() method if the observer has been disposed.
I understand that calling CompositeDisposable.dispose() means that my Subscriber's onSuccess or onError methods won't be called, but shouldn't the exception be ignored too? Instead the application is crashing because the RuntimeException isn't caught.

Here is the Single, the line with the comment can throw a RuntimeException, if the exception is thrown before a call to the .dispose() method, it get's caught and the error is sent to the subscriber, but if the exception is thrown AFTER a call to .dispose() the app crashes.

public Single<Submission> getSubmission(final String threadId, final CommentSort sort) {
        return Single.create(new SingleOnSubscribe<Submission>() {
            @Override
            public void subscribe(SingleEmitter<Submission> e) throws Exception {
                // some irrelevant code

                try {
                    submission = reddit.getSubmission(sr); // Can throw RuntimeException
                    e.onSuccess(submission);
                } catch (Exception ex) {
                    e.onError(ex);
                }
            }
        });
    }  

Code where I subscribe to it:

disposables.add(someCompletable
                .andThen(service.getSubmission(threadId, CommentSort.HOT))
                .subscribeOn(schedulerProvider.io())
                .observeOn(schedulerProvider.ui())
                .subscribeWith(new DisposableSingleObserver<Submission>() {
                    @Override
                    public void onSuccess(Submission submission) {
                        // Handle result
                    }

                    @Override
                    public void onError(Throwable e) {
                        // Handle error
                    }
                })
        );

Stacktrace:

E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-2
Process: com.gmail.jorgegilcavazos.ballislife.debug, PID: 15242
java.lang.RuntimeException: Unable to parse JSON: [{"kind": "Listing", "data": {"modhash": null, "children": [{"kind": "t3", "data
at net.dean.jraw.util.JrawUtils.fromString(JrawUtils.java:182)
at net.dean.jraw.http.RestResponse.<init>(RestResponse.java:64) 
at net.dean.jraw.http.OkHttpAdapter.execute(OkHttpAdapter.java:81)
at net.dean.jraw.http.RestClient.execute(RestClient.java:120)
at net.dean.jraw.RedditClient.execute(RedditClient.java:143)
at net.dean.jraw.RedditClient.execute(RedditClient.java:137)
at net.dean.jraw.RedditClient.getSubmission(RedditClient.java:287)
at com.gmail.jorgegilcavazos.ballislife.network.API.RedditService$10.subscribe(RedditService.java:311)
at io.reactivex.internal.operators.single.SingleCreate.subscribeActual(SingleCreate.java:39)
at io.reactivex.Single.subscribe(Single.java:2656)
at io.reactivex.internal.operators.single.SingleDelayWithCompletable$OtherObserver.onComplete(SingleDelayWithCompletable.java:70)
at io.reactivex.internal.disposables.EmptyDisposable.complete(EmptyDisposable.java:67)
at io.reactivex.internal.operators.completable.CompletableEmpty.subscribeActual(CompletableEmpty.java:27)
at io.reactivex.Completable.subscribe(Completable.java:1592)
at io.reactivex.internal.operators.single.SingleDelayWithCompletable.subscribeActual(SingleDelayWithCompletable.java:36)
at io.reactivex.Single.subscribe(Single.java:2656)

回答1:


Found the answer:

RxJava 2 is designed so that no errors can be lost. So when the sequence ends or gets cancelled the emitter has nowhere to send the error, so it gets routed to the RxJavaPlugins.onError.
Unlike 1.x, 2.x by default calls Thread.currentThread().getUncaughtExceptionHandler().uncaughtException()which crashes an Android app.

Source
Similar stackoverflow question

In my case, since the subscriber has been disposed I no longer care about the errors that the emitter could throw, so the emitter should check that it has not been disposed of before calling onError()

try {
      Submission submission = redditClient.getSubmission(sr);
      e.onSuccess(submission);
} catch (Exception ex) {
      if (!e.isDisposed()) {
           e.onError(ex);
      }
}


来源:https://stackoverflow.com/questions/43532034/runtimeexception-thrown-and-not-caught-in-rxjava2-single-after-it-has-been-dispo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!