RxJava 操作符--defer

2 篇文章 0 订阅
1 篇文章 0 订阅

原文作者: [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()方法。
我喜欢这个解决方案有两个原因:

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

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


我彦神镇楼^_^

我彦神镇楼^_^

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值