rxJava2 在复杂流中组合单一的、可能的、可完成的
rxJava2 Combining Single, Maybe, Completable in complex Streams
我对新的 RxJava Sources
感到非常兴奋,例如:Single
、Maybe
、Completable
,它使您的界面 类 更干净并防止在创建 'Source' 过程中犯了很多错误(例如忘记调用 onComplete()
)
但是需要大量的样板文件才能将它们组合成一个复杂的流。
例如我们有常见的 Android 加载和缓存数据的情况。假设我们有 2 个来源 api
和 cache
,我们想合并它:
public interface Api {
Single<Integer> loadFromNetwork();
}
public interface Cache {
Maybe<Integer> loadFromCache(); //maybe because cache might not have item.
}
让我们尝试结合它:
final Single<Integer> result = cache.loadFromCache()
.switchIfEmpty(api.loadFromNetwork());
它不会编译,因为 Maybe
没有重载 Maybe.switchIfEmpty(Single):Single
所以我们必须转换一切:
final Single<Integer> result = cache.loadFromCache()
.switchIfEmpty(api.loadFromNetwork().toMaybe())
.toSingle();
另一种可能的组合方式也需要 сonversion:
final Single<Integer> result = Observable.concat(
cache.loadFromCache().toObservable(),
api.loadFromNetwork().toObservable()
).firstOrError();
因此,如果不进行许多会增加代码噪音并创建大量额外对象的转换,我看不出有任何方法可以使用新源。
由于这些问题,我无法使用 Single
、Maybe
、Completable
并继续到处使用 Observable
。
所以我的问题是:
结合 Single
、Maybe
的最佳实践是什么?
Completable
.
为什么这些 Sources 没有重载以使梳理更容易。
为什么这些源没有共同的祖先并将其用作
switchIfEmpty
和其他方法的参数?
P.S. 有人知道为什么这些 类 没有任何共同的层次结构吗?
从我的角度来看,如果某些代码可以与 Completable
一起工作,它也可以与 Single
和 Maybe
?
一起工作
也许我不是一个全面的答案,但我试着回答你的具体用例:
我认为你的合并任务的目的是从缓存中获取数据,如果结果为空你想调用远程 api:
final Single<List<Integer>> single = api.call();
Maybe<List<Integer>> maybe = disk.call();
Single <List<Integer>> composedSingle = maybe.flatMapSingle(new Function<List<Integer>, SingleSource<?>>() {
@Override
public SingleSource<?> apply(List<Integer> integers) throws Exception {
if(integers.isEmpty()) return single;
else return Single.just(integers);
}
});
我没有测试过,但我认为可能是一个可能的解决方案(不确定是否最好)。
我知道这个问题已经很老了,但似乎还没有公认的答案。
从 RxJava 2.1.4 开始,他们最终添加:
public final Single<T> switchIfEmpty(SingleSource<? extends T> other)
因此您可以将链简化为:
cache.switchIfEmpty(api)
如果你有最新版本的 RxJava,这应该是这种情况的首选方法。请注意,该方法带有 @Experimental
注释,因此将来可能会再次更改。
2017 年 9 月 22 日发布的 RxJava 2.1.4 添加了所需的重载 Maybe.switchIfEmpty(Single):Single
.
所以如果我们想合并以下 类:
public interface Api {
Single<Integer> loadFromNetwork();
}
public interface Cache {
Maybe<Integer> loadFromCache(); //maybe because cache might not have item.
}
我们终于可以做到:
final Single<Integer> result = cache.loadFromCache()
.switchIfEmpty(api.loadFromNetwork());
Rx 团队在 Maybe
、Single
、Observable
中添加了额外的重载,从而简化了它们的组合。
至于发布2.1.16,我们有以下组合Maybe
、Single
和Completable
的方法:
可能: flatMapSingleElement(Single):Maybe
, flatMapSingle(Single):Single
, switchIfEmpty(Single):Maybe
, flatMapCompletable(Completable):Completable
单身: flatMapMaybe(Maybe):Maybe
, flatMapCompletable(Completable):Completable
可完成: andThen(Single):Single
, andThen(Maybe):Maybe
我对新的 RxJava Sources
感到非常兴奋,例如:Single
、Maybe
、Completable
,它使您的界面 类 更干净并防止在创建 'Source' 过程中犯了很多错误(例如忘记调用 onComplete()
)
但是需要大量的样板文件才能将它们组合成一个复杂的流。
例如我们有常见的 Android 加载和缓存数据的情况。假设我们有 2 个来源 api
和 cache
,我们想合并它:
public interface Api {
Single<Integer> loadFromNetwork();
}
public interface Cache {
Maybe<Integer> loadFromCache(); //maybe because cache might not have item.
}
让我们尝试结合它:
final Single<Integer> result = cache.loadFromCache()
.switchIfEmpty(api.loadFromNetwork());
它不会编译,因为 Maybe
没有重载 Maybe.switchIfEmpty(Single):Single
所以我们必须转换一切:
final Single<Integer> result = cache.loadFromCache()
.switchIfEmpty(api.loadFromNetwork().toMaybe())
.toSingle();
另一种可能的组合方式也需要 сonversion:
final Single<Integer> result = Observable.concat(
cache.loadFromCache().toObservable(),
api.loadFromNetwork().toObservable()
).firstOrError();
因此,如果不进行许多会增加代码噪音并创建大量额外对象的转换,我看不出有任何方法可以使用新源。
由于这些问题,我无法使用 Single
、Maybe
、Completable
并继续到处使用 Observable
。
所以我的问题是:
结合
Single
、Maybe
的最佳实践是什么?Completable
.为什么这些 Sources 没有重载以使梳理更容易。
为什么这些源没有共同的祖先并将其用作
switchIfEmpty
和其他方法的参数?
P.S. 有人知道为什么这些 类 没有任何共同的层次结构吗?
从我的角度来看,如果某些代码可以与 Completable
一起工作,它也可以与 Single
和 Maybe
?
也许我不是一个全面的答案,但我试着回答你的具体用例:
我认为你的合并任务的目的是从缓存中获取数据,如果结果为空你想调用远程 api:
final Single<List<Integer>> single = api.call();
Maybe<List<Integer>> maybe = disk.call();
Single <List<Integer>> composedSingle = maybe.flatMapSingle(new Function<List<Integer>, SingleSource<?>>() {
@Override
public SingleSource<?> apply(List<Integer> integers) throws Exception {
if(integers.isEmpty()) return single;
else return Single.just(integers);
}
});
我没有测试过,但我认为可能是一个可能的解决方案(不确定是否最好)。
我知道这个问题已经很老了,但似乎还没有公认的答案。
从 RxJava 2.1.4 开始,他们最终添加:
public final Single<T> switchIfEmpty(SingleSource<? extends T> other)
因此您可以将链简化为:
cache.switchIfEmpty(api)
如果你有最新版本的 RxJava,这应该是这种情况的首选方法。请注意,该方法带有 @Experimental
注释,因此将来可能会再次更改。
2017 年 9 月 22 日发布的 RxJava 2.1.4 添加了所需的重载 Maybe.switchIfEmpty(Single):Single
.
所以如果我们想合并以下 类:
public interface Api {
Single<Integer> loadFromNetwork();
}
public interface Cache {
Maybe<Integer> loadFromCache(); //maybe because cache might not have item.
}
我们终于可以做到:
final Single<Integer> result = cache.loadFromCache()
.switchIfEmpty(api.loadFromNetwork());
Rx 团队在 Maybe
、Single
、Observable
中添加了额外的重载,从而简化了它们的组合。
至于发布2.1.16,我们有以下组合Maybe
、Single
和Completable
的方法:
可能: flatMapSingleElement(Single):Maybe
, flatMapSingle(Single):Single
, switchIfEmpty(Single):Maybe
, flatMapCompletable(Completable):Completable
单身: flatMapMaybe(Maybe):Maybe
, flatMapCompletable(Completable):Completable
可完成: andThen(Single):Single
, andThen(Maybe):Maybe