在RxJava2中处理null

时间:2016-09-29 23:15:15

标签: rx-java

即将到来的RxJava2 release其中一项重要更改是null不再被接受为流元素,即以下代码将引发异常:Observable.just(null)

老实说,我对这种变化有着复杂的感觉,我的一部分理解它会强制执行干净的API,但是当这可能是一个问题时,我可以看到一些用例。

例如,在我的应用程序中,我有一个内存缓存:

@Nullable CacheItem findCacheItem(long id);

CacheItem可能不存在于缓存中,因此方法可能会返回空值。

与Rx *一起使用的方式如下:

Observable<CacheItem> getStream(final long id) {
    return Observable.fromCallable(new Callable<CacheItem>() {
        @Override public CacheItem call() throws Exception {
            return findCacheItem(id);
        }
    });
}

所以使用这种方法,我可能在我的流中得到null,这是完全有效的情况,所以它在接收端正确处理 - 假设UI在缓存中没有项目时改变其状态:

Observable.just(user)
          .map(user -> user.getName())
          .map(name -> convertNameToId(name))
          .flatMap(id -> getStream(id))
          .map(cacheItem -> getUserInfoFromCacheItem(cacheItem))
          .subscribe(
              userInfo -> {
                  if(userInfo != null) showUserInfo();
                  else showPrompt();
              }
          );

使用RxJava2我不再允许在流中发布null,因此我需要将我的CacheItem包装到其他类中,并使我的流生成该包装,或者进行相当大的体系结构更改。

将每个流元素包装成可空的副本对我来说都不合适。

我错过了一些基本的东西吗?

看起来像我这样的情况非常受欢迎,所以我很好奇在RxJava2中新的“无空”政策,解决这个问题的建议策略是什么?

修改 请参阅RxJava GitHub repo

中的后续对话

4 个答案:

答案 0 :(得分:17)

嗯,有几种方法可以代表你想要的东西。

一种选择是使用Func<TResult>

Observable<Optional<CacheItem>>

然后使用Observable<Optional<CacheItem>> getStream(final long id) { return Observable.defer(() -> { return Observable.just(Optional.ofNullable(findCacheItem(id))); }); } public static <T> Transformer<Optional<T>, T> deoptionalize() { return src -> src.flatMap(item -> item.isPresent() ? Observable.just(item.get()) : Observable.empty(); } 从可选映射到非可选的Observable。

答案 1 :(得分:2)

您可以使用RxJava2-Nullable处理RxJava2中的空值。

根据您的情况,您可以:

showPrompt

要在Observable.just(user) .map(user -> user.getName()) .map(name -> convertNameToId(name)) .flatMap(id -> getStream(id).onNullRun(() -> showPrompt())) .map(cacheItem -> getUserInfoFromCacheItem(cacheItem)) .subscribe(userInfo -> showUserInfo()); NullableObservable<CacheItem> getStream(final long id) { return RxNullable.fromCallable(() -> findCacheItem(id)).observable(); } 为空时调用它,您可以执行以下操作:

{{1}}

答案 2 :(得分:1)

作为另一种解决方案,您可以添加静态实例CacheItem.NULL,并在没有缓存数据时将其返回给订阅者

Single
    .concat(loadFromMemory(), loadFromDb(), loadFromServer())
    .takeFirst { it != CachedItem.NULL }
    .subscribe(

答案 3 :(得分:0)

可能的解决方案是使用Maybe.switchIfEmpty

示例:

public static <T> Maybe<T> maybeOfNullable(T value) {
    return value == null ? Maybe.empty() : Maybe.just(value);
}

maybeOfNullable(user)
        .map(user -> user.getName())
        .map(name -> convertNameToId(name))
        .flatMap(id -> getStream(id))
        .map(cacheItem -> getUserInfoFromCacheItem(cacheItem))
        // perform another action in case there are no any non null item emitted
        .switchIfEmpty(Maybe.fromAction(() -> showPrompt()))
        .subscribe(userInfo -> showUserInfo());