使用Observable.flatMap时的错误处理

时间:2017-09-30 01:58:52

标签: rx-java2

下面有一个示例程序可以复制我的问题。

问题:

  1. flatMap转换应用于某些Observable
  2. 订阅前面提到的Observable,将订阅存储在某个地方
  3. Observable自然终止
  4. 之前处置上述订阅
  5. 在映射器函数返回的Observable中,引发Exception
  6. Flatmap运算符不知道如何处理Exception,引发它,程序崩溃/退出
  7. 首选/预期行为:

    • 错误应该传播到我的onError处理程序,而不是在调用RxJavaPlugins#onError时崩溃程序

    罪魁祸首是ObservableFlatMap中的代码片段。问题是,一旦处理完父节点,对addThrowable的调用将返回false。因此,错误永远不会传播到onError

    @Override
    public void onError(Throwable t) {
      if (parent.errors.addThrowable(t)) {
          if (!parent.delayErrors) {
              parent.disposeAll();
          }
          done = true;
          parent.drain();
      } else {
          RxJavaPlugins.onError(t);
      }
    }
    

    在这种情况下我该怎么办?我需要一个像flatMap一样的运算符,并将错误传播到我的onError处理程序而不是崩溃我的程序。

    这是我的Android应用程序的真实场景。当用户退出窗口/活动时,将自动处理订阅,并且由于InterruptedIOException s而在处理后可能会引发异常。

    复制问题的代码

    import io.reactivex.Observable;
    import io.reactivex.disposables.Disposable;
    import io.reactivex.plugins.RxJavaPlugins;
    import io.reactivex.schedulers.Schedulers;
    
    public class Main {
    
      public static void main(String[] args) throws InterruptedException {
        RxJavaPlugins.setErrorHandler((throwable)->{
          System.out.println("Please don't come through here");
          throwable.printStackTrace();
        });
        Disposable disposable = Observable.just(1)
            .subscribeOn(Schedulers.computation())
            .flatMap((item)->{
              return Observable.just(1)
                  .doOnNext((arg)->Thread.sleep(1000))
                  .doOnNext((arg)->{
                    throw new RuntimeException("Error");
                  });
            })
            .subscribe(System.out::println, (throwable)->{
              System.out.println("Please come through here");
              throwable.printStackTrace();
            });
        Thread.sleep(500);
        disposable.dispose();
        Thread.sleep(1000);
      }
    
    }
    

    执行输出

    Please don't come through here
    io.reactivex.exceptions.UndeliverableException: java.lang.InterruptedException: sleep interrupted
      at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:349)
      at io.reactivex.internal.operators.observable.ObservableFlatMap$InnerObserver.onError(ObservableFlatMap.java:573)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:119)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onError(ObservableDoOnEach.java:119)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:99)
      at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
      at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.subscribeInner(ObservableFlatMap.java:162)
      at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:139)
      at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
      at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
      at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
      at io.reactivex.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:38)
      at io.reactivex.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:26)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:748)
    Caused by: java.lang.InterruptedException: sleep interrupted
      at java.lang.Thread.sleep(Native Method)
      at Main.lambda$null$1(Main.java:18)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:95)
      ... 22 more
    

    预期/首选输出

    Please come through here
    java.lang.RuntimeException: Error
      at Main.lambda$null$2(Main.java:19)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:95)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:103)
      at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
      at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.subscribeInner(ObservableFlatMap.java:162)
      at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:139)
      at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
      at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
      at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
      at io.reactivex.Observable.subscribe(Observable.java:10903)
      at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
      at io.reactivex.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:38)
      at io.reactivex.internal.schedulers.ScheduledDirectTask.call(ScheduledDirectTask.java:26)
      at java.util.concurrent.FutureTask.run(FutureTask.java:266)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
      at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
      at java.lang.Thread.run(Thread.java:748)
    

1 个答案:

答案 0 :(得分:1)

问题出在.subscribeOn(Schedulers.computation())之前的flatMap。当你dispose中断线程产生平面地图可观察数据时会破坏整个订阅。要解决这个问题,你应该在flatMap之后或之内指定订阅,或者在另一个帖子中观察它。

工作示例:

RxJavaPlugins.setErrorHandler((throwable) -> {
        System.out.println("Please don't come through here");
        throwable.printStackTrace();
    });
    Disposable disposable = Observable.just(1)
            .flatMap((item) -> {
                return Observable.just(1)

                        .doOnNext((arg) -> Thread.sleep(1000))
                        .doOnNext((arg) -> {
                            throw new IllegalStateException("Error");
                        })
                        .subscribeOn(Schedulers.computation());
            })
            .subscribe(System.out::println,
                    (throwable) -> {
                        System.out.println("Please come through here");
                        throwable.printStackTrace();
                    });
    Thread.sleep(500);
    disposable.dispose();
    Thread.sleep(1000);