Hot and Cold observables
可观察序列有两种形式,称为“热”和“冷”,具有重要差异。在本章中,我们将解释每种类型的含义以及对于您作为Rx开发人员的意义。
冷可观察量(Cold observables)
冷可观察序列当它们被订阅时,它们运行它们的序列,从一开始就向每个用户呈现序列。冷可观察序列的一个例子是Observable.interval。无论何时创建以及何时订阅,它都将为每个订阅者生成相同的序列。
输出:
两个订阅者不会同时收到相同的值,即使他们都订阅了相同的observable。确实看到了相同的序列,除了他们每个人都认为它们在订阅时已经开始。
到目前为止,我们在本指南中看到的代码示例都是冷可观察序列,因为冷可观察量更易于推理。使用Observable.create创建的每个可观察对象都是冷可观察的。这包括我们所见过的所有缩写,例如just,range,timer和from。
冷可观察量不一定对每个用户呈现相同的序列。例如,如果observable连接到数据库并发出查询结果,则实际值将取决于订阅时数据库的状态。事实上,订阅者将从一开始就接收整个查询,这使得这种可观察的冷却。
热可观察量(Hot observables)
热可观察值的发出独立于个人订阅。他们有自己的时间表,无论是否有人在听,都会发生事件。一个例子是鼠标事件。无论是否有订阅,鼠标都会生成事件。订阅完成后,观察者会在事件发生时收到这些事件。您没有收到,并且您不希望收到自启动系统以来鼠标所做的所有事情的回顾。取消订阅时,它也不会阻止鼠标生成事件。你只是没有收到它们。如果您重新订阅,您将再次看到当前事件,而无法回顾您错过的内容。
Publish
有很多方法可以将冷观测值变为热观测值,反之亦然。使用publish()运算符,Cold Observable变得"热"。
publish返回一个ConnectableObservable <T>,它是Observable <T>的扩展,带有三个附加方法
有一个变量采用选择器在发布序列之前转换序列
selector可以执行我们在observable上学到的任何操作。这样做的用处是为选择器进行单个订阅,可以根据需要重复使用。如果没有这个重载,重用observable可能会导致多个订阅。
此方法返回Observable <T>而不是ConnectableObservable <T>,因此我们即将讨论的连接功能不适用于此。
connect
ConnectableObservable最初不会发出任何内容。当调用connect时,它将为其source observable(我们称之为发布的那个)创建一个新的订阅。它将开始接收事件并将其推送给其订阅者。所有订阅者将同时收到相同的事件,因为他们实际上共享相同的订阅。
输出:
Disconnecting
我们在connect的定义中看到,这个方法返回一个Subscription,就像Observable.subscribe一样。您可以使用该引用来终止ConnectableObservable的订阅。这将阻止事件传播给观察者,但它不会取消订阅ConnectableObservable。如果再次调用connect,ConnectableObservable将启动新订阅,旧观察者将再次开始接收值。
输出:
通过再次调用connect重新启动时,将创建一个新订阅。如果source observable是冷的,那意味着整个序列重新启动。
如果您不想终止连接,而是想取消订阅hot observable,则可以使用subscribe方法返回的订阅。
输出:
refCount
只要有订阅者,ConnectableObservable.refCount就会返回已连接的Observable <T>。
输出:
我们在这里看到,在有refCount订阅者之前,序列才会开始。如果它们全部消失,则连接停止。如果以后有更多,则会启动新连接。
replay
replay类似于ReplaySubject。连接后,它将开始收集值。一旦新的观察者订阅了observable,它就会将所有收集的值重放到它上面。一旦它赶上,它将与其他观察者并行接收值。
输出:
replay返回一个类似于publish的ConnectableObservable,因此我们可以使用相同的方法取消订阅或创建一个refCount observable。
replay有8个重载
它们是提供3个参数中的一个或多个的不同方式:bufferSize,selector和time(加上时间单位)。
- bufferSize确定要存储和重放的最大项目数。订阅后,observable将重放最后一个bufferSize项目数,旧的被遗弃。这对于节省内存很有用。
- time, unit确定元素在被遗弃之前。订阅后,observable将replay比时间更新的项目。
- 选择器将以与发布(选择器)相同的方式转换重放的observable。
这是bufferSize的一个例子:
输出:
当我们连接时,源开始以1s间隔发射序列0,1,2,3,4。我们在订阅之前睡了4.5秒,这意味着源已经发出0,1,2,3。0和1从缓冲区中掉落,因此只重放2和3。当发射4时,我们正常接收它。
提供时间窗口时,值会根据时间从缓冲区中消失。
输出:
cache
cache操作符具有类似的重放功能,但隐藏了ConnectableObservable并删除了订阅的管理。第一个观察者到达时,内部ConnectableObservable被订阅。后续订阅者具有从缓存中重放的先前值,并且不会导致对源可观察对象的新订阅。
输出:
在这个例子中,我们看到序列不是在创建observable时开始,而是在第一个用户在500ms之后到达时开始。第二个订阅者在订阅时赶上了早期的值,并且通常会收到未来的值。
需要注意的一点是,如果所有订阅都消失了,内部的ConnectableObservable不会取消订阅,就像refCount那样。一旦第一个订阅到达,将一次性返回观察和缓存源。这很重要,因为我们不能再远离无限的可观察者了。值将继续缓存,直到源终止或内存不足。指定容量的重载也不是解决方案,因为容量是作为优化提示接收的,并且实际上不会限制缓存的大小。
输出:
在此示例中,doOnNext在生成和从源可观察文件缓存时打印值,而doOnSubscribe和doOnUnsubscribe在缓存后显示订阅者。我们看到值的排放从第一次订阅开始,但忽略了我们取消订阅的事实。
Multicast
share方法是Observable.publish().refCount()的别名。它允许您的订阅者共享订阅,只要有订阅者,订阅就会保留。
下节再续!
原文:https://github.com/Froussios/Intro-To-RxJava/blob/master/Part%203%20-%20Taming%20the%20sequence/6.%20Hot%20and%20Cold%20observables.md
有什么讨论的内容,可以加我公众号: