Connectable Observable Operators

本文的主题为处理 Connectable Observable 的操作符。

这里的 Observable 实质上是可观察的数据流。

RxJava操作符(九)Connectable Observable Operators

冷数据流 / 热数据流 / 可连接的数据流

  • 冷数据流只有在订阅后才开始发送数据。

    订阅者可以保证观察到冷数据流最初所发送的数据。但是不同的订阅者所观察到的不是同一份数据,是冷数据流专为自己发送的数据。冷数据流不能共享数据。
  • 热数据流从创建之初就开始发送数据,无论有没有订阅者都一直在发送数据。

    订阅者只能观察到订阅之后热数据流所发送的数据。但是所有的订阅者所观察到的都是同一份数据。热数据流能够共享数据。
  • 可连接的数据流在连接之后将转变为热数据流,无论有没有订阅者都开始发送数据。
  • Interval 所创建的数据流是冷数据流

  • RxNET
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
var observable = Observable.Interval(TimeSpan.FromSeconds(1));
using (observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)))
{
Thread.Sleep(TimeSpan.FromSeconds(1.5));
using (observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)))
Console.ReadKey();
}
/*
first subscription : 0
first subscription : 1
second subscription : 0
first subscription : 2
second subscription : 1
first subscription : 3
...
*/
  • RxJava
val cold = Observable
.interval(200, TimeUnit.MILLISECONDS)
.take(5)
cold.dump("First")
Thread.sleep(500)
cold.dump("Second")
/*
First: onNext: 0
First: onNext: 1
First: onNext: 2
Second: onNext: 0
First: onNext: 3
Second: onNext: 1
First: onNext: 4
First: onComplete
Second: onNext: 2
Second: onNext: 3
Second: onNext: 4
Second: onComplete
*/
  • RxSwift
let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
_ = interval
.subscribe(onNext: { print("Subscription: 1, Event: \($0)") })
delay(5) {
_ = interval
.subscribe(onNext: { print("Subscription: 2, Event: \($0)") })
}
/*
Subscription: 1, Event: 0
Subscription: 1, Event: 1
Subscription: 1, Event: 2
Subscription: 1, Event: 3
Subscription: 1, Event: 4
Subscription: 1, Event: 5
Subscription: 2, Event: 0
Subscription: 1, Event: 6
Subscription: 2, Event: 1
Subscription: 1, Event: 7
Subscription: 2, Event: 2
Subscription: 1, Event: 8
...
*/

Connect / Publish / PublishLast / MultiCast

ReactiveX - Connect operator

ReactiveX - Publish operator

Reactive Extensions再入門 その36「ColdからHotへ!Publishメソッドと参照カウンタ?RefCountメソッド」

Reactive Extensions再入門 その37「ColdからHotへ!その他のPublish系メソッド」

Publish / PublishLast 将普通数据流发布(转变)为可连接的数据流。

可连接的数据流必须经 Connect 连接后才开始发送数据。

Connect 连接可连接的数据流,将可连接的数据流变为热数据流并开始发送数据。

经过 Publish 发布,Connect 连接后的热数据流在订阅之后可以观察到订阅之后热数据流发送的数据。

经过 PublishLast 发布,Connect 连接后的热数据流在订阅之后只能观察到订阅之后热数据流最后发送的数据。

Publish / PublishLast 的返回值代表数据流对象,销毁该对象将销毁源数据流。

Connect 的返回值代表连接对象,销毁该对象将断开连接,被断开连接的热数据流将变回可连接的数据流。

Multicast 的语义如下

  • .Publish() = .Multicast(new Subject<T>)
  • .PublishLast() = .Multicast(new AsyncSubject<T>)
  • .Replay() = .Multicast(new ReplaySubject<T>)



  • RxNET
var observable = Observable.Interval(TimeSpan.FromSeconds(1)).Publish();
observable.Connect();
using (observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)))
{
Thread.Sleep(TimeSpan.FromSeconds(2));
using (observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)))
Console.ReadKey();
}
/*
first subscription : 0
first subscription : 1
second subscription : 1
first subscription : 2
second subscription : 2
...
*/
var period = TimeSpan.FromSeconds(1);
var observable = Observable.Interval(TimeSpan.FromSeconds(1)).Publish();
using (observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i)))
{
Thread.Sleep(TimeSpan.FromSeconds(2));
using (observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i)))
{
observable.Connect();
Console.ReadKey();
}
}
/*
first subscription : 0
second subscription : 0
first subscription : 1
second subscription : 1
first subscription : 2
second subscription : 2
...
*/
var period = TimeSpan.FromSeconds(1);
var observable = Observable.Interval(period).Publish();
observable.Subscribe(i => Console.WriteLine("subscription : {0}", i));
var exit = false;
while (!exit)
{
Console.WriteLine("Press enter to connect, esc to exit.");
var key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Enter)
{
var connection = observable.Connect(); //--Connects here--
Console.WriteLine("Press any key to dispose of connection.");
Console.ReadKey();
connection.Dispose(); //--Disconnects here--
}
if (key.Key == ConsoleKey.Escape)
{
exit = true;
}
}
/*
Press enter to connect, esc to exit.
Press any key to dispose of connection.
subscription : 0
subscription : 1
subscription : 2
subscription : 3
Press enter to connect, esc to exit.
Press any key to dispose of connection.
subscription : 0
subscription : 1
subscription : 2
Press enter to connect, esc to exit.
...
*/
var period = TimeSpan.FromSeconds(1);
var observable = Observable.Interval(period)
.Do(l => Console.WriteLine("Publishing {0}", l)) //Side effect to show it is running
.Publish();
var subscription2 = observable.Connect();
Console.WriteLine("Press any key to subscribe");
Console.ReadKey();
var subscription = observable.Subscribe(i => Console.WriteLine("subscription : {0}", i));
Console.WriteLine("Press any key to unsubscribe.");
Console.ReadKey();
subscription.Dispose();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
subscription2.Dispose();
/*
Press any key to subscribe
Publishing 0
Publishing 1
Publishing 2
Press any key to unsubscribe.
Publishing 3
subscription : 3
Publishing 4
subscription : 4
Publishing 5
subscription : 5
Press any key to exit.
Publishing 6
Publishing 7
...
*/
  • PublishLast
var period = TimeSpan.FromSeconds(1);
var observable = Observable.Interval(period)
.Take(5)
.Do(l => Console.WriteLine("Publishing {0}", l)) //side effect to show it is running
.PublishLast();
observable.Connect();
Console.WriteLine("Press any key to subscribe");
Console.ReadKey();
var subscription = observable.Subscribe(i => Console.WriteLine("subscription : {0}", i));
Console.WriteLine("Press any key to unsubscribe.");
Console.ReadKey();
subscription.Dispose();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
/*
Press any key to subscribe
Publishing 0
Publishing 1
Publishing 2
Press any key to unsubscribe.
Publishing 3
Publishing 4
subscription : 4
Press any key to exit.
*/
  • RxJava
val cold = Observable.interval(200, TimeUnit.MILLISECONDS).publish()
cold.connect()
val s1 = cold.dump("First")
Thread.sleep(500)
val s2 = cold.dump("Second")
readLine()
s1.dispose()
s2.dispose()
/*
First: onNext: 0
First: onNext: 1
First: onNext: 2
Second: onNext: 2
First: onNext: 3
Second: onNext: 3
...
*/
val connectable = Observable.interval(200, TimeUnit.MILLISECONDS).publish()
var s = connectable.connect()
connectable.dump()
Thread.sleep(1000)
println("Closing connection")
s.dispose()
Thread.sleep(1000)
println("Reconnecting")
s = connectable.connect()
connectable.dump()
readLine()
s.dispose()
/*
onNext: 0
onNext: 1
onNext: 2
onNext: 3
Closing connection
onNext: 4
Reconnecting
onNext: 0
onNext: 1
onNext: 2
...
*/
val connectable = Observable.interval(200, TimeUnit.MILLISECONDS).publish()
connectable.connect()
val s1 = connectable.dump("First")
Thread.sleep(500)
val s2 = connectable.dump("Second")
Thread.sleep(500)
println("Disposing second")
s2.dispose()
readLine()
s1.dispose()
/*
First: onNext: 0
First: onNext: 1
First: onNext: 2
Second: onNext: 2
First: onNext: 3
Second: onNext: 3
Disposing second
First: onNext: 4
First: onNext: 5
First: onNext: 6
...
*/
  • RxSwift
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.publish()
_ = intSequence
.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
delay(2) { _ = intSequence.connect() }
delay(4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
delay(6) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
/*
Subscription 1:, Event: 0
Subscription 1:, Event: 1
Subscription 2:, Event: 1
Subscription 1:, Event: 2
Subscription 2:, Event: 2
Subscription 1:, Event: 3
Subscription 2:, Event: 3
Subscription 3:, Event: 3
Subscription 1:, Event: 4
Subscription 2:, Event: 4
Subscription 3:, Event: 4
...
*/
let subject = PublishSubject<Int>()
_ = subject
.subscribe(onNext: { print("Subject: \($0)") })
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.multicast(subject)
_ = intSequence
.subscribe(onNext: { print("\tSubscription 1:, Event: \($0)") })
delay(2) { _ = intSequence.connect() }
delay(4) {
_ = intSequence
.subscribe(onNext: { print("\tSubscription 2:, Event: \($0)") })
}
delay(6) {
_ = intSequence
.subscribe(onNext: { print("\tSubscription 3:, Event: \($0)") })
}
/*
Subject: 0
Subscription 1:, Event: 0
Subject: 1
Subscription 1:, Event: 1
Subscription 2:, Event: 1
Subject: 2
Subscription 1:, Event: 2
Subscription 2:, Event: 2
Subject: 3
Subscription 1:, Event: 3
Subscription 2:, Event: 3
Subscription 3:, Event: 3
...
*/

RefCount

ReactiveX - RefCount operator

Reactive Extensions再入門 その36「ColdからHotへ!Publishメソッドと参照カウンタ?RefCountメソッド」

RefCount 将可连接的数据流重新变回普通数据流。

RefCount 还给数据流加上引用计数语义,订阅时引用计数器加一,取消订阅时引用计数器减一,订阅者都取消订阅时数据流自动销毁。

  • RxNET
var period = TimeSpan.FromSeconds(1);
var observable = Observable.Interval(period)
.Do(l => Console.WriteLine("Publishing {0}", l)) //side effect to show it is running
.Publish()
.RefCount();
//observable.Connect(); Use RefCount instead now
Console.WriteLine("Press any key to subscribe");
Console.ReadKey();
var subscription = observable.Subscribe(i => Console.WriteLine("subscription : {0}", i));
Console.WriteLine("Press any key to unsubscribe.");
Console.ReadKey();
subscription.Dispose();
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
/*
Press any key to subscribe
Press any key to unsubscribe.
Publishing 0
subscription : 0
Publishing 1
subscription : 1
Publishing 2
subscription : 2
Press any key to exit.
*/
  • RxJava
val cold = Observable.interval(200, TimeUnit.MILLISECONDS).publish().refCount()
var s1 = cold.dump("First")
Thread.sleep(500)
val s2 = cold.dump("Second")
Thread.sleep(500)
println("Dispose Second")
s2.dispose()
Thread.sleep(500)
println("Dispose First")
s1.dispose()
println("First connection again")
Thread.sleep(500)
s1 = cold.dump("First")
readLine()
s1.dispose()
/*
First: onNext: 0
First: onNext: 1
First: onNext: 2
Second: onNext: 2
First: onNext: 3
Second: onNext: 3
Dispose Second
First: onNext: 4
First: onNext: 5
First: onNext: 6
Dispose First
First connection again
First: onNext: 0
First: onNext: 1
First: onNext: 2
...
*/

Replay / Cache

ReactiveX - Replay operator

Reactive Extensions再入門 その38「ColdからHotへ!その他のPublish系メソッド2」

Replay 给热数据流加上 Replay 语义,即缓存所有的数据,使后来的订阅者也能观察到订阅之前所发送的数据。

Replay 可以指定缓冲区的大小。

  • RxNET
Console.WriteLine(MethodBase.GetCurrentMethod().Name);
var hot = Observable.Interval(TimeSpan.FromSeconds(1))
.Take(3)
.Publish();
hot.Connect();
Thread.Sleep(TimeSpan.FromSeconds(1.5)); //Run hot and ensure a value is lost.
var observable = hot.Replay();
observable.Connect();
observable.Subscribe(i => Console.WriteLine("first subscription : {0}", i));
Thread.Sleep(TimeSpan.FromSeconds(1.5));
observable.Subscribe(i => Console.WriteLine("second subscription : {0}", i));
Console.ReadKey();
observable.Subscribe(i => Console.WriteLine("third subscription : {0}", i));
Console.ReadKey();
/*
first subscription : 1
second subscription : 1
first subscription : 2
second subscription : 2
third subscription : 1
third subscription : 2
*/
  • RxJava
val cold = Observable.interval(200, TimeUnit.MILLISECONDS).replay()
cold.connect()
println("Subscribe first")
val s1 = cold.dump("First")
Thread.sleep(700)
println("Subscribe second")
val s2 = cold.dump("Second")
Thread.sleep(500)
readLine()
s1.dispose()
s2.dispose()
/*
Subscribe first
First: onNext: 0
First: onNext: 1
First: onNext: 2
Subscribe second
Second: onNext: 0
Second: onNext: 1
Second: onNext: 2
First: onNext: 3
Second: onNext: 3
First: onNext: 4
Second: onNext: 4
...
*/
val source = Observable.interval(1000, TimeUnit.MILLISECONDS)
.take(5)
.replay(2)
source.connect()
Thread.sleep(4500)
source.dump()
/*
onNext: 2
onNext: 3
onNext: 4
onComplete
*/
val source = Observable.interval(1000, TimeUnit.MILLISECONDS)
.take(5)
.replay(2000, TimeUnit.MILLISECONDS)
source.connect()
Thread.sleep(4500)
source.dump()
/*
onNext: 2
onNext: 3
onNext: 4
onComplete
*/
val obs = Observable.interval(100, TimeUnit.MILLISECONDS)
.take(5)
.cache()
Thread.sleep(500)
obs.dump("First")
Thread.sleep(300)
obs.dump("Second")
/*
First: onNext: 0
First: onNext: 1
First: onNext: 2
Second: onNext: 0
Second: onNext: 1
Second: onNext: 2
First: onNext: 3
Second: onNext: 3
First: onNext: 4
Second: onNext: 4
First: onComplete
Second: onComplete
*/
val obs = Observable.interval(100, TimeUnit.MILLISECONDS)
.take(5)
.doOnNext { println(it) }
.cache()
.doOnSubscribe { println("Subscribed") }
.doOnDispose { println("Disposed") }
val subscription = obs.subscribe()
Thread.sleep(150)
subscription.dispose()
/*
Subscribed
0
Disposed
1
2
3
4
*/
  • RxSwift

RxSwift: share vs replay vs shareReplay

let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.replay(5)
_ = intSequence
.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
delay(2) { _ = intSequence.connect() }
delay(4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
delay(8) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
/*
Subscription 1:, Event: 0 (after 3 secs)
Subscription 2:, Event: 0 (after 4 secs)
Subscription 1:, Event: 1 (after 4 secs)
Subscription 2:, Event: 1 (after 4 secs)
Subscription 1:, Event: 2 (after 5 secs)
Subscription 2:, Event: 2 (after 5 secs)
Subscription 1:, Event: 3 (after 6 secs)
Subscription 2:, Event: 3 (after 6 secs)
Subscription 1:, Event: 4 (after 7 secs)
Subscription 2:, Event: 4 (after 7 secs)
Subscription 3:, Event: 0 (after 8 secs)
Subscription 3:, Event: 1 (after 8 secs)
Subscription 3:, Event: 2 (after 8 secs)
Subscription 3:, Event: 3 (after 8 secs)
Subscription 3:, Event: 4 (after 8 secs)
Subscription 1:, Event: 5 (after 9 secs)
Subscription 2:, Event: 5 (after 9 secs)
Subscription 3:, Event: 5 (after 9 secs)
...
*/

ReactiveX 学习笔记(10)可连接的数据流的更多相关文章

  1. ReactiveX 学习笔记(5)合并数据流

    Combining Observables 本文的主题为合并 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(四)Combining An ...

  2. ReactiveX 学习笔记(4)过滤数据流

    Filtering Observables 本文主题为过滤 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(三)Filtering Deb ...

  3. ReactiveX 学习笔记(3)转换数据流

    Transforming Observables 本文的主题为转换 Observable 的操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操作符(二)Transform ...

  4. ReactiveX 学习笔记(2)创建数据流

    操作符(Operators) Rx 的操作符能够操作(创建/转换/组合) Observable. Creating Observables 本文主题为创建/生成 Observable 的操作符. 这里 ...

  5. TCP/IP详解学习笔记(10)-TCP连接的建立与中止

    TCP是一个面向连接的协议,所以在连接双方发送数据之前,都需要首先建立一条连接.这和前面讲到的协议完全不同.前面讲的所有协议都只是发送数据而已,大多数都不关心发送的数据是不是送到,UDP尤其明显,从编 ...

  6. ReactiveX 学习笔记(0)学习资源

    ReactiveX 学习笔记 ReactiveX 学习笔记(1) ReactiveX 学习笔记(2)创建数据流 ReactiveX 学习笔记(3)转换数据流 ReactiveX 学习笔记(4)过滤数据 ...

  7. thinkphp学习笔记10—看不懂的路由规则

    原文:thinkphp学习笔记10-看不懂的路由规则 路由这部分貌似在实际工作中没有怎么设计过,只是在用默认的设置,在手册里面看到部分,艰涩难懂. 1.路由定义 要使用路由功能需要支持PATH_INF ...

  8. golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息

    golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...

  9. mybatis学习笔记(10)-一对一查询

    mybatis学习笔记(10)-一对一查询 标签: mybatis mybatis学习笔记10-一对一查询 resultType实现 resultMap实现 resultType和resultMap实 ...

  10. 《C++ Primer Plus》学习笔记10

    <C++ Primer Plus>学习笔记10 <<<<<<<<<<<<<<<<<&l ...

随机推荐

  1. ArcGIS for android添加图层几何体

    GraphicLayer lyr; Map<String,Object> attr = new HashMap<String,Object>(); attr.put(this. ...

  2. switch case 变量初始化问题

    今天再写alsa的时候遇到一个稀奇古怪的问题,网上看了下资料,摘出来入下 代码: int main() { ; switch(a) { : ; break; : break; default: bre ...

  3. Nginx 分布式session共享问题

    在集群的时候每次访问,都会被代理转到不同的服务器,那么在这些服务器之间如何共享session? 解决方式1:session复制 只能在window下好使,web服务器解决(广播机制,将一台机器上的se ...

  4. struts2的result的类型配置简介

    一.在strut2的action处理完成后,就应该向用户返回结果信息result 根据以下代码作为实例分析: <package name="Hello" extends=&q ...

  5. APIO 2018选圆圈

    #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #i ...

  6. python学习之----导航树

    findAll 函数通过标签的名称和属性来查找标签 .但是如果你需要通过标签在文档中的位 置来查找标签,该怎么办?这就是导航树(Navigating Trees)的作用.在第1 章里,我们 看过用单一 ...

  7. 蓝桥杯Java真题解析

    上个月参加蓝桥杯省赛拿了个省一,自从比赛完之后就一直没怎么写代码了,还有一个多月就要国赛了,从现在开始准备下国赛,但是我也不想学什么算法,而且我还在准备考研,所以就打算只做下历年的真题,争取国赛拿个国 ...

  8. android 开发 对话框Dialog详解

    转载请注明出处:红亮的专栏:http://blog.csdn.net/liang5630/article/details/44098899 Android中的对话框形式大致可分为五种:分别是一般对话框 ...

  9. 纯CSS3实现垂直居中的九种方法

    浏览时看到的资料,每个都做了测试,很好,就先收了~ 测试的是谷歌浏览器,没有任何问题,用360,IE11,火狐,搜狗浏览器做测试时,第五个方法在360,搜狗,和IE11有点问题,第七个在IE11有问题 ...

  10. Yii框架中使用SRBAC作为权限管理模块时遇到的问题

    Yii框架中使用SRBAC作为权限管理模块时遇到的问题   看到Yii中提供RBAC的插件,SRBAC,就想用用. 结果按照手册上的安装办法,整来整去,安装完了,可就是进不了权限管理界面. 最后想到, ...