0

我正在改编一些来自三词地址的示例代码,以便通过他们的 Java SDK 访问他们的 API。它使用 RXJava。

示例代码是:

Observable.fromCallable(() -> wrapper.convertTo3wa(new Coordinates(51.2423, -0.12423)).execute())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(result -> {
            if (result.isSuccessful()) {
                Log.i("MainActivity", String.format("3 word address: %s", result.getWords()));
            } else {
                Log.e("MainActivity", result.getError().getMessage());
            }
        });

首先。这会在构建时发出弃用警告并发出 IDE 警告 ( Result of 'Observable.subscribe()' is ignored)。

为了解决第一个问题,我Disposable myDisposable = Observable. 这个对吗?(添加位置见下文)

接下来我需要添加一个超时,以便在请求超时时可以显示警告等。为此,我已添加.timeout(5000, TimeUnit.MILLISECONDS)到构建器中。

这行得通,但timeouts 似乎对Observables 起作用的方式是它们抛出异常,我不知道如何捕获和处理该异常。

我现在拥有的是:

Disposable myDisposable = Observable.fromCallable(() -> wrapper.convertTo3wa(new Coordinates(51.2423, -0.12423)).execute())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .timeout(5000, TimeUnit.MILLISECONDS)
        .subscribe(result -> {
            if (result.isSuccessful()) {
                Log.i("MainActivity", String.format("3 word address: %s", result.getWords()));
            } else {
                Log.e("MainActivity", result.getError().getMessage());
            }
        });

这构建并运行良好,并且未显示 API/弃用警告,但是当没有可用网络时,此正确超时并引发未处理的异常。

所以,代码似乎是正确的,但究竟如何添加异常处理来捕获TimeoutException抛出的超时?

我已经尝试了很多东西,包括:try-catch在整体周围添加一个子句Observable- 这会警告TimeoutException`try; 中的代码不会抛出该警告;并添加一个错误处理程序。

添加错误处理程序让我最接近,所以下面的代码是我所得到的:

Disposable myDisposable = Observable.fromCallable(() -> wrapper.convertTo3wa(new Coordinates(51.2423, -0.12423)).execute())
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .timeout(5000, TimeUnit.MILLISECONDS)
        .subscribe(result -> {
            if (result.isSuccessful()) {
                Log.i("MainActivity", String.format("3 word address: %s", result.getWords()));
            } else {
                Log.e("MainActivity", result.getError().getMessage());
            }
         }, error -> {
             runOnUiThread(new Runnable() {
                 @Override
                 public void run() {
                     myTextView.setText(R.string.network_not_available);
                 }
             });
         });

这会正确捕获超时并更新我的 UI 而不会出错,但是当网络恢复时,似乎 Observable 可能正在尝试返回并引发空指针异常。

(更新,无论网络是否恢复,这个NPE实际上可能会在短时间内被抛出......但它总是在网络恢复时抛出。)

我得到FATAL EXCEPTION: RxCachedThreadScheduler-1并且java.lang.NullPointerException: Callable returned a null value. Null values are generally not allowed in 3.x operators and sources.

我是否需要销毁Observable或其他东西来防止 NPE?

4

2 回答 2

1

您需要在调用中添加onError处理程序subscribe

    .subscribe(result -> {
        if (result.isSuccessful()) {
            Log.i("MainActivity", String.format("3 word address: %s", result.getWords()));
        } else {
            Log.e("MainActivity", result.getError().getMessage());
        }
     },
     error -> {
         // handle error here
     });

当异常进入没有 onError 处理程序的订阅调用时,它将抛出 OnErrorNotImplementedException,如下所示:

io.reactivex.exceptions.OnErrorNotImplementedException: The exception was not handled due to missing onError handler in the subscribe() method call. Further reading: https://github.com/ReactiveX/RxJava/wiki/Error-Handling | java.util.concurrent.TimeoutException: The source did not signal an event for 1 seconds and has been terminated.

添加 onError 处理程序将阻止这种情况,并且将调用 onError 处理程序。

于 2021-08-19T17:36:01.757 回答
0

这里发生了一些事情:

首先。这会在构建时发出弃用警告并发出 IDE 警告(忽略“Observable.subscribe()”的结果)。

subscribe()返回一个Disposable。这个想法是,当您不再对接收 observable 的输出感兴趣时,您调用dispose()可处置的并且工作终止。这也可以防止内存泄漏。

举个例子,假设你有一个 Activity,然后你启动一个 Observable 来运行一个长的网络查询,最终将一些东西发布到 Activity UI。如果用户在此任务完成之前离开,或者 Activity 以其他方式被破坏,那么您不再对其输出感兴趣,因为不再有 UI 可以发布到。所以你可以打电话dispose()onStop()

所以,代码似乎是正确的,但是到底如何添加异常处理来捕获抛出的超时 TimeoutException 呢?

使用error块输入subscribe是一种选择,但还有其他选择。例如,如果你想继续使用你的Result类,你可以使用类似onErrorReturn(throwable -> Result.error(throwable)). 显然我在猜测那个类的样子:

.timeout(5000, TimeUnit.MILLISECONDS)
.onErrorReturn(throwable -> Result.errorWithMessage(R.string.network_not_available))
.subscribe(result -> {
  if (result.isSuccessful()) {
    Log.i("MainActivity", String.format("3 word address: %s", result.getWords()));
  } else {
    myTextView.setText(result.getErrorMessage());
  }
});

java.lang.NullPointerException:可调用返回空值。3.x 运算符和源中通常不允许空值。

这个:

wrapper.convertTo3wa(new Coordinates(51.2423, -0.12423)).execute()

正在返回 null。您可以执行以下操作:

Observable.fromCallable(() -> {
  Result<?> out = wrapper.convertTo3wa(new Coordinates(51.2423, -0.12423)).execute();
  if(out == null)
    out = Result.error(/*Returned null*/);
  }
  return out;
}
于 2021-08-20T12:59:55.067 回答