RxJava 操作符--defer

xiaoxiao2021-02-28  6

原文作者: [Dan Lew]

文章链接: [ Deferring Observable code until subscription in RxJava]

正文

延迟Observable代码运行直到被订阅(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()方法。 我喜欢这个解决方案有两个原因:

它比.create()简单, 不需要手动调用 onCompleted()。 它使用内置的操作符,所以它们(很可能)是正确实现的。

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


我彦神镇楼^_^

转载请注明原文地址: https://www.6miu.com/read-1150263.html

最新回复(0)