Rxjava cold/hot Observable
create
Observable分为cold以及hot两种,cold主要是静态的,每次subscribe都是从头开始互不干扰,而hot的在同一时刻获得的值是一致的
cold Observable
使用create创建的Observable都是属于cold的Observable
@Test
public void coldObs() throws InterruptedException {
Observable obs=Observable.create(sub->{
//在新线程上emit对象
new Thread(()->{
int i=0;
while(i<5){
sub.onNext(i++);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}}).start();
});
obs.subscribe(x->System.out.println("1st sub "+x));
Thread.sleep(1000);
obs.subscribe(x->System.out.println("2nd sub "+x));
while(true){
Thread.sleep(10000);
}
}
-----输出-----
1st sub 0
1st sub 1
2nd sub 0
1st sub 2
2nd sub 1
1st sub 3
2nd sub 2
1st sub 4
2nd sub 3
2nd sub 4
可以看到两个subscribe相隔1s订阅,两个值互不相关。
hot Observable
coldObs可以转换为hotObservable,hot主要是使用在比如鼠标操作等事件上的
@Test
public void hotObs() throws InterruptedException {
ConnectableObservable obs=Observable.create(sub->{
//在新线程上emit对象
new Thread(()->{
int i=0;
while(i<5){
sub.onNext(i++);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}}).start();
}).publish();
//开始emit对象
obs.connect();
obs.subscribe(x->System.out.println("1st sub "+x));
Thread.sleep(1000);
obs.subscribe(x->System.out.println("2nd sub "+x));
while(true){
Thread.sleep(10000);
}
}
-----输出-----
1st sub 1
1st sub 2
1st sub 3
2nd sub 3
1st sub 4
2nd sub 4
使用publish和connect之后就开始向subscriber发送对象,无论当前有几个subscriber,同一时刻subscriber得到的值也是一样的
源码分析
RxJava中有内置的钩子函数可以将函数注册在RxJavaHooks的各个方法上来改变各个环节的操作,包括Observable创建,运行时等
Observable的create方法只是注册了对应emit的OnSubscribe对象
public static <T> Observable<T> create(OnSubscribe<T> f) {
//调用protected构造方法,这里使用RxJavaHooks的onCreate方法
return new Observable<T>(RxJavaHooks.onCreate(f));
}
protected Observable(OnSubscribe<T> f) {
this.onSubscribe = f;
}
正真运行Observable的是subscriber订阅时触发的
public final Subscription subscribe(Subscriber<? super T> subscriber) {
return Observable.subscribe(subscriber, this);
}
static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
if (subscriber == null) {
throw new IllegalArgumentException("subscriber can not be null");
}
if (observable.onSubscribe == null) {
throw new IllegalStateException("onSubscribe function can not be null.");
}
//调用subscriber的onStart方法
subscriber.onStart();
//使用SafeSubscriber包装原有的Subscriber,SafeSubscriber装饰原来的Subscriber保证当调用onComplete或onError后不会再调用任何方法。
if (!(subscriber instanceof SafeSubscriber)) {
subscriber = new SafeSubscriber<T>(subscriber);
}
try {
//使用JavaHooks的onObservableStart拦截的onSubscribe,并调用subscriber
RxJavaHooks.onObservableStart(observable, observable.onSubscribe).call(subscriber);
//当结束调用RxJavaHooks的onObservableReturn拦截方法
return RxJavaHooks.onObservableReturn(subscriber);
} catch (Throwable e) {
...
}
}
这个是cold Observable的流程,下面看下Observable的publish和connect的逻辑
//Observable.java
//publish方法包装原来的Observable返回ConnectableObservable
public final ConnectableObservable<T> publish() {
return OperatorPublish.create(this);
}
//OperatorPublish.java
public static <T> ConnectableObservable<T> create(Observable<? extends T> source) {
//订阅在原始Observable上的Subscriber
final AtomicReference<PublishSubscriber<T>> curr = new AtomicReference<PublishSubscriber<T>>();
//ConnectableObservable的OnSubscribe,提供外界Subscriber订阅
OnSubscribe<T> onSubscribe = new OnSubscribe<T>() {
@Override
public void call(Subscriber<? super T> child) {
for (;;) {
PublishSubscriber<T> r = curr.get();
if (r == null || r.isUnsubscribed()) {
//这个Subscriber是用于订阅到原始Observable上的,这里只是初始化,并没有开始订阅
PublishSubscriber<T> u = new PublishSubscriber<T>(curr);
u.init();
if (!curr.compareAndSet(r, u)) {
continue;
}
r = u;
}
InnerProducer<T> inner = new InnerProducer<T>(r, child);
//将订阅的子subscriber添加到PublishSubscriber上
if (r.add(inner)) {
child.add(inner);
child.setProducer(inner);
break; // NOPMD
}
}
}
};
return new OperatorPublish<T>(onSubscribe, source, curr);
}
//connect方法将PublishSubscriber订阅到原始的Observable,
//ConnectableObservble.java
public final Subscription connect() {
final Subscription[] out = new Subscription[1];
//调用OperatorPublish的connect方法
connect(new Action1<Subscription>() {
@Override
public void call(Subscription t1) {
out[0] = t1;
}
});
return out[0];
}
//OperatorPublish.java
public void connect(Action1<? super Subscription> connection) {
boolean doConnect;
PublishSubscriber<T> ps;
//防止竞态条件使用CAS来初始化PublishSubscriber
for (;;) {
ps = current.get();
if (ps == null || ps.isUnsubscribed()) {
PublishSubscriber<T> u = new PublishSubscriber<T>(current);
u.init();
if (!current.compareAndSet(ps, u)) {
continue;
}
ps = u;
}
doConnect = !ps.shouldConnect.get() && ps.shouldConnect.compareAndSet(false, true);
break; // NOPMD
}
connection.call(ps);
if (doConnect) {
//如果之前没有订阅过,那么就订阅到原始的Observable上
source.unsafeSubscribe(ps);
}
}
//PublishSubscriber.java
//这个是订阅到原始Observable上的Subscriber,当触发onNext时的逻辑
public void onNext(T t) {
//将原始Observable发出的对象放入一个队列
if (!queue.offer(NotificationLite.next(t))) {
onError(new MissingBackpressureException());
} else {
//调用dispatch方法可以将队列的内容发送个订阅的子Subscriber
dispatch();
}
}
//将值分发到各个子Subscriber上
void dispatch() {
...
//从队列中取得值
Object v = queue.poll();
...
//处理null
T value = NotificationLite.getValue(v);
...
//循环所有的InnerProducer(之前的在onSubscribe中add在Subsciber上的)
for (InnerProducer<T> ip : ps) {
if (ip.get() > 0L) {
try {
//把value传递给child的onNext
ip.child.onNext(value);
} catch (Throwable t) {
ip.unsubscribe();
Exceptions.throwOrReport(t, ip.child, value);
continue;
}
ip.produced(1);
}
}
...
}
hot的Observable就是自己监听原始的Observable然后广播给注册在上的子Subscriber,从而达到能够让所有子Subscriber取得一样的数据。
Rxjava cold/hot Observable的更多相关文章
- RxJava 设计理念 观察者模式 Observable lambdas MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- RxJava && Agera 从源码简要分析基本调用流程(2)
版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/124 来源:腾云阁 https://www.qclo ...
- Rxjava异常处理
异常处理 在Rxjava订阅的Observable有时会抛出异常,在RxJava中有两大类策略,一个是准备备用的Observable,在发生异常时将subscriber订阅到新的Observable上 ...
- RxJava 和 RxAndroid 一 (基础)
1.RxJava 项目地址 https://github.com/ReactiveX/RxJava 2.RxAndroid 项目地址 https://github.com/ReactiveX/R ...
- 用RxJava处理嵌套请求
用RxJava处理嵌套请求 互联网应用开发中由于请求网络数据频繁,往往后面一个请求的参数是前面一个请求的结果,于是经常需要在前面一个请求的响应中去发送第二个请求,从而造成"请求嵌套" ...
- 78. Android之 RxJava 详解
转载:http://gank.io/post/560e15be2dca930e00da1083 前言 我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Fli ...
- Retrofit与RXJava整合
Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API.下面我用对比的方式来介绍 Retrofit 的 RxJava 版 ...
- RxJava学习入门
RxJava是什么 一个词:异步. RxJava 在 GitHub 主页上的自我介绍是 "a library for composing asynchronous and event-bas ...
- 给 Android 开发者的 RxJava 详解
我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个 ...
随机推荐
- 细说WebSocket - Node篇
在上一篇提高到了 web 通信的各种方式,包括 轮询.长连接 以及各种 HTML5 中提到的手段.本文将详细描述 WebSocket协议 在 web通讯 中的实现. 一.WebSocket 协议 1. ...
- Hyper-v 安装CentOS 7 (其他虚拟机一样参考)
平台之大势何人能挡? 带着你的Net飞奔吧!http://www.cnblogs.com/dunitian/p/4822808.html hyper-v安装很多人没弄过,我这里介绍一下.(其他虚拟机参 ...
- CENTOS 6.5 平台离线编译安装 PHP5.6.6
一.下载php源码包 http://cn2.php.net/get/php-5.6.6.tar.gz/from/this/mirror 二.编译 编译之前可能会缺少一些必要的依赖包,加载一个本地yum ...
- 神马玩意,EntityFramework Core 1.1又更新了?走,赶紧去围观
前言 哦,不搞SQL了么,当然会继续,周末会继续更新,估计写完还得几十篇,但是我会坚持把SQL更新完毕,绝不会烂尾,后续很长一段时间没更新的话,不要想我,那说明我是学习新的技能去了,那就是学习英语,本 ...
- [C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密
string 与 String,大 S 与小 S 之间没有什么不可言说的秘密 目录 小写 string 与大写 String 声明与初始化 string string 的不可变性 正则 string ...
- ASP.NET Core 中文文档 第四章 MVC(4.5)测试控制器逻辑
原文: Testing Controller Logic 作者: Steve Smith 翻译: 姚阿勇(Dr.Yao) 校对: 高嵩(Jack) ASP.NET MVC 应用程序的控制器应当小巧并专 ...
- Effective前端2:优化html标签
div { float: left; } .keyboard > div + div { margin-left: 8px; } --> div{display:table-cell;ve ...
- 调用微信退款接口或发红包接口时出现System.Security.Cryptography.CryptographicException: 出现了内部错误 解决办法
我总结了一下出现证书无法加载的原因有以下三个 1.证书密码不正确,微信证书密码就是商户号 解决办法:请检查证书密码是不是和商户号一致 2.IIS设置错误,未加载用户配置文件 解决办法:找到网站使用的应 ...
- MVC还是MVVM?或许VMVC更适合WinForm客户端
最近开始重构一个稍嫌古老的C/S项目,原先采用的技术栈是『WinForm』+『WCF』+『EF』.相对于现在铺天盖地的B/S架构来说,看上去似乎和Win95一样古老,很多新入行的,可能就没有见过经典的 ...
- PHP设计模式(二)工厂方法模式(Factory Method For PHP)
简单工厂简述: 简单工厂模式实现了生产产品类的代码跟客户端代码分离,在工厂类中你可以添加需要生成长跑的逻辑代码(new 产品类),但是问题来了,优秀的代码是符合"开闭原则"如果你要 ...