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. [UE4]暂停游戏、退出游戏、游戏输入模式

    游戏主界面WB_Main蓝图 Set Game Paused:暂停游戏 Show Mouse Cursor:显示鼠标 Set Input Mode:设置游戏输入模式(游戏和UI).仅仅游戏.仅仅UI( ...

  2. MySQL 迁移并搭建主从(实践)

    第一阶段 一.数据的初始化 1.老主库 关闭sql_log_binset sql_log_bin = off; 创建导出用户grant all privileges on *.* to 'dump'@ ...

  3. 【LeetCode】2. Add Two Numbers 两数相加

    给出两个 非空 的链表用来表示两个非负的整数.其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字. 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和 ...

  4. Android 打开高德地图、百度地图进行导航;打开第三方App去导航;

    抽成工具类了,复制下来就能直接用了,直接看代码吧: 高德地图Url Api: http://lbs.amap.com/api/amap-mobile/guide/android/navigation ...

  5. day10学习笔记整理

    函数对象函数是第一类对象: 指的是函数名指向的值(函数)可以被当作数据去使用 1. 可以被引用 2. 可以当作参数传给另外一个函数 3. 可以当作一个函数的返回值 4. 可以当作容器类型的元素   l ...

  6. 网易微专业 UI设计师

    网易云课堂的UI设计师微专业,需要的留言

  7. 微信小程序获取用户信息

    App({ appData: { userInfo:{ user_portraitUrl: "", user_nick: "", user_gender: 0, ...

  8. tkinter menu

    python] view plain copy '''''Tkinter教程之Menu篇''' '''''1.创建一个简单的Menu''' # 添加菜单hello和quit,将hello菜单与hell ...

  9. 《锋利的JQuery》中重写超链接与图片提示效果

    代码部分: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <met ...

  10. 关于Linux(时间网路同步)

    Linux 时间同步只针对命令行界面,图形界面请自行摸索. 转自Linux下ntpdate时间同步