【问题标题】:Getting error "Callable returned null" when using RxJava2使用 RxJava2 时出现错误“可调用返回 null”
【发布时间】:2017-10-01 16:43:15
【问题描述】:

我在我的 android 项目中使用 RxJava2。

我正在使用以下代码创建Observable

public Observable<AlbumDetails> loadAlbumFromAlbumId(final String albumId) {
    return Observable.fromCallable(new Callable<AlbumDetails>() {
        @Override
        public AlbumDetails call() throws Exception {
             AlbumDetails albumDetails = getAlbumDetails(albumId);     
             return albumDetails;   
       });
}

从可观察到的,我在 DisposableObserver 的 onError 方法中收到以下错误

Callable returned null

这在使用 RxJava 时不会发生。

【问题讨论】:

  • 在编译时没有给出错误,也没有在调试 apk 中,而是给你一个发布的 apk 的机会。

标签: java android rx-java reactive-programming rx-java2


【解决方案1】:

我曾经有这样的代码:

Observable<R> obs = Observable.fromCallable(this::work);

work() 可能会返回 null,正如您所指出的,RxJava 2 对此并不满意。

方法一

Observable<R> obs = Maybe.fromCallable(this::work).toObservable();

通过这种方式,最终消费者——观察者——只有在 work() 有任何返回时才会启动。如果 work() 返回 null 那么它和订阅一个空的 Observer 是一样的;什么都没有发生。

方法二

Observable<R> obs = Observable.create(e -> {
    R r = work();

    if (r != null) {
        e.onNext(r);
    }

    e.onComplete();
});

方法三:

将每个发射包装在 Optional = 出于多种原因的坏主意。

主要是因为我只在我的 API 中使用 Optional,如果它是预期的,并且有点像“正常”的场景,你不时得到一个 null。如果 null 不是预期的或非常罕见,可能是同一消费者完成另一个 API 调用的直接结果,那么我返回 null 并让消费者在这些特殊情况下处理它,而不是让每个消费者都处理 Optional地点。

【讨论】:

    【解决方案2】:

    如维基中给出的:

    What's Different in 2.0

    RxJava 2.x 不再接受空值。将 null 作为流元素会立即导致 NullPointerException 并因此调用 onError 方法。

    这样做主要是为了避免由于应用程序中的NullPointerException 而导致崩溃。

    我通过一种相当简单的方法解决了这个问题。 我检查了该值是否为 null,如果是,我将 null 替换为占位符对象。

    还存在其他更复杂的方法来解决这个问题,但对于我的用例来说,这种简单的方法就足够了。

    【讨论】:

      【解决方案3】:

      RxJava 2.x 不再接受空值而不实现错误处理程序

      示例

      Observable.fromCallable(() -> null)
          .subscribe(System.out::println, Throwable::printStackTrace);
      
      Observable.just(1).map(v -> null)
          .subscribe(System.out::println, Throwable::printStackTrace);
      

      你的问题的解决方案

      当你调用/订阅这个方法时,如下所示

      Observable<AlbumDetails> testObservable= Observable.create(emitter -> { ... });
      testObservable.subscribe(t -> System.out.print(t),Throwable::printStackTrace);
      

      【讨论】:

        【解决方案4】:

        假设getAlbumDetails(albumId)方法在数据不可用或错误的情况下返回null,并且你愿意在这种情况下优雅地完成你的流,你可以使用这样的东西:

        public Observable<AlbumDetails> loadAlbumFromAlbumId(String albumId) {
            return Maybe.fromCallable(() -> getAlbumDetails(albumId))
                .onErrorComplete()
                .toObservable();
        };
        

        为了更好的可读性,我已将匿名类替换为 lambda,但您当然可以保持原样。

        【讨论】:

          【解决方案5】:

          您还可以将返回值包装在 Optional (Java 8) 中。以及在您的订阅中使用 optional.isPresent() 和 optional.get() 的地图。

          【讨论】:

            【解决方案6】:

            我想出了这个解决方法:

            首先创建了一个包装类:

            class NullableObject<T>(val value: T?)
            

            然后像这样为 Single 创建了一个扩展函数:

            inline fun <T> runInSingle(
                    crossinline block: () -> T,
                    crossinline callback: (T?) -> Unit,
                    crossinline onError: (Throwable) -> Unit) {
            
               Single.fromCallable {
                  return@fromCallable block().toNullableObject()
               }.subscribeOn(Schedulers.io())
                       .observeOn(AndroidSchedulers.mainThread())
                       .subscribe { result, error ->
                          if (error != null) {
                             onError(error)
                          } else {
                             callback(result.value)
                          }
                       }
            }
            
            fun <T> T.toNullableObject(): NullableObject<T> = NullableObject(this)
            

            如何使用:

            runInSingle({
                     doSomethingInBackgroundWhichMayReturnNull()
                  }, { result ->
                     if(result != null) {
                       doSomethingWithTheNonNullResult()
                     } else {
                       doSomethingWithTheNullResult()
                     }
                  }, { error ->
                     error.printStackTrace()
                  })
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-05-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-12-29
              相关资源
              最近更新 更多