2

RuntimeExceptions 应该表示编程错误,我希望我的应用程序在我的 observables 中的某些东西抛出 RuntimeException 时崩溃。

做这个的最好方式是什么?现在我正在考虑这个解决方案(它是 Kotlin,但我希望它是可以理解的)

fun <T> Observable<T>.subscribeCrashOnRuntimeException(onNext: (T) -> Unit, onError: (Throwable) -> Unit) {
  this.subscribe({
    onNext(it)
  }, { e ->
    if (e is RuntimeException) {
      throw e
    } else {
      onError(e)
    }
  })
}

fun usageExample() {
  val observable = Observable.just(1)
  observable.subscribeCrashOnRuntimeExceptions(
    { next -> Log.d("TAG", "next: $next") },
    { e -> Log.d("TAG", "error: $e") }
  )
}

但我对此表示怀疑。例如,使用此解决方案很难偶尔“捕获”特定的 RuntimeExceptions。也许有一种众所周知的方法来处理我只是不知道如何谷歌的情况?

4

1 回答 1

1

我认为处理运行时(又名未检查)或常规(又名已检查)异常应该没有太大区别。如今,两者都被广泛使用,并且可以根据特定情况恢复或不可恢复。

处理错误的反应式方法是:

  1. 通过onErrorResumeNextonErrorReturn运算符;这些允许检查错误并可能从中恢复
  2. 通过retry*运营商家族;这些允许检查错误并可能通过重新订阅(例如重试网络调用)从错误中恢复
  3. 通过onError您的订阅者的回调;顺便说一句,如果您不提供这样的回调,错误将以常规 Java 方式重新抛出,因此您的程序崩溃

相关主题:如何在没有丑陋的 instanceof 的情况下处理 Retrofit Rx onError 中的不同类型错误

还要注意以常规 Java 方式抛出异常的缺点:

  • 消息处理时的调用栈与定义消息处理规则时的调用栈不同;这意味着捕获此类异常以及解释堆栈跟踪可能非常困难
  • 调度程序捕获的异常可能不会导致程序终止;即你的程序可能最终挂在损坏的状态

示例代码

Observable.fromCallable(() -> {
    ...
    if (ok) return "Success!";
    else throw new RuntimeException("Failure at source");
})
.map(s -> {
    ... processing is bypassed in case of an error
})
.map(s -> {
    ...
    if (...) return s.upperCase();
    else throw new RuntimeException("Failure during processing");
})
.onErrorReturn(e -> {
    if (e.getMessage().contains("processing"))
        return "Recovered";
    throw Exceptions.propagate(e); // let it continue as an error
})
.subscribe(s -> println("got result: " + s),
           e -> println("got error: " + e);

所有异常都被 RxJava 捕获并沿着定义的路径传递。

onError*运算符的作用类似于中间catch块。

订阅者的onError回调就像顶级catch块一样。

有关该主题的更多链接:

于 2017-01-12T08:12:16.147 回答