赞
踩
原文作者: [Dan Lew]
文章链接:
[ Deferring Observable code until subscription in RxJava]
正文
我喜欢使用RxJava的defer()作为一种工具,以确保在订阅时(而不是创建时)运行Observable的代码。我已经写了一些关于延期的文章,但我想在这里更详细地讨论一下。
假设你有这个数据类:
public class SomeType {
private String value;
public void setValue(String value) {
this.value = value;
}
public Observable<String> valueObservable() {
return Observable.just(value);
}
}
你认为我运行这端代码时会打印什么?
SomeType instance = new SomeType();
Observable<String> value = instance.valueObservable();
instance.setValue("Some Value");
value.subscribe(System.out::println);
如果你觉得是“Some Value”,那你就错了。它实际上输出了“null”,因为在调用just()的时候,value值还没有初始化。
just()、from()和其他Observable创建工具在创建时存储数据的值,而不是在订阅时存储。在这种情况下,这不是我期望的行为——我希望valueObservable()能够在请求时表示当前值。
一个解决方案是使用Observable. create(),因为它允许您精确地控制每个订阅者的序列
public Observable<String> valueObservable() {
return Observable.create(subscriber -> {
subscriber.onNext(value);
subscriber.onCompleted();
});
}
现在valueObservable()将在订阅时发射出当前的值。它大致等价于Observable.just()。只是被创建的Observable在被订阅时会检索value当前的值(而不是创建时的)。
这里唯一的问题是,自从阅读了David Karnok的一系列关于操作符的优秀文章后,我一直对编写自定义操作符保持谨慎。我从这个系列中得到的主要结论是,操作符很难正确地编写。看看这篇文章,它告诉你为了支持反压力和取消订阅Observable.just()需要做出什么改变。
虽然上面的代码可以工作了,但我如何知道它将永远适用于RxJava的未来版本?我怎么知道我已经安全地覆盖了所有的情形,比如背压和取消订阅?我不是操作符开发方面的专家。因此,除非必要,我尽量避免使用自定义操作符。
这里有一个不适用自定义操作的替代方案:
public Observable<String> valueObservable() {
return Observable.defer(() -> Observable.just(value));
}
我所做的仅仅是用defer()来包装原始代码,但这就是我所期待的。在订阅之前,defer()内的所有代码都不会执行。当有人请求数据时,我们就会调用just()方法。
我喜欢这个解决方案有两个原因:
defer()的唯一缺点是它在每次获得订阅用户时创建一个新的Observable。create()可以为每个订阅用户使用相同的函数,因此更高效。通常,我们需要在性能和优化之间做权衡。
因为学习的原因,上面的代码很简单,但实际上我们可以用一个
BehaviorSubject
来代替它。让我们来看看更复杂的东西。
假设我们想要一个将数据写入磁盘的方法,然后返回该数据。
这是使用defer()的一种实现:
public Observable<SomeType> createSomeType(String value) {
return Observable.defer(() -> {
SomeType someType = new SomeType();
someType.setValue(value);
try {
db.writeToDisk(someType);
} catch (IOException e) {
return Observable.error(e);
}
return Observable.just(someType);
});
}
这个示例更复杂;它将数据写入磁盘,如果存在问题,则调用onError。但是基本的想法仍然是一样的:我们不需要任何代码来执行直到被订阅。
有多种方法可以解决上述问题。defer()只是其中之一,但我觉得它很方便。
总结:defer操作符是cold
创建型操作符,参数为实现了ObservableSource
接口的类; defer创建的Observable直到被Observer订阅才会开始发射数据
作者文中的代码是基于RxJava1.x的 在2.x版本中会出现错误 究其原因就是:
Null values are generally not allowed in 2.x operators and sources.
在2.x版本中RxJava不允许出现被发射的条目为null或操作符函数参数null
我彦神镇楼^_^
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。