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 ,并且使用的场景越来越多 .而最近这几个 ...
随机推荐
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- VisualVM通过jstatd方式远程监控远程主机
配置好权限文件 [root@test bin]# cd $JAVA_HOME/bin [root@test bin]# vim jstatd.all.policy grant codebase &qu ...
- 分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间)
分享一个SQLSERVER脚本(计算数据库中各个表的数据量和每行记录所占用空间) 很多时候我们都需要计算数据库中各个表的数据量和每行记录所占用空间 这里共享一个脚本 CREATE TABLE #tab ...
- C语言 · 阶乘计算 · 基础练习
问题描述 输入一个正整数n,输出n!的值. 其中n!=1*2*3*-*n. 算法描述 n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法.使用一个数组A来表示一个大整数a,A[0]表 ...
- Bootstrap-Select 动态加载数据的小记
关于前端框架系列的可以参考我我刚学Bootstrap时候写的LoT.UI http://www.cnblogs.com/dunitian/p/4822808.html#lotui bootstrap- ...
- 在ASP.NET Core应用中如何设置和获取与执行环境相关的信息?
HostingEnvironment是承载应用当前执行环境的描述,它是对所有实现了IHostingEnvironment接口的所有类型以及对应对象的统称.如下面的代码片段所示,一个HostingEnv ...
- C#数组,List,Dictionary的相互转换
本篇文章会向大家实例讲述以下内容: 将数组转换为List 将List转换为数组 将数组转换为Dictionary 将Dictionary 转换为数组 将List转换为Dictionary 将Dicti ...
- jQuery幻灯片插件autoPic
原文地址:Jquery自定义幻灯片插件 插件效果图: 演示地址:autoPic项目地址:autoPic 欢迎批评指正!
- 笔记:Memory Notification: Library Cache Object loaded into SGA
笔记:Memory Notification: Library Cache Object loaded into SGA在警告日志中发现一些这样的警告信息:Mon Nov 21 14:24:22 20 ...
- MySQL,MariaDB:Undo | Redo [转]
本文是介绍MySQL数据库InnoDB存储引擎重做日志漫游 00 – Undo LogUndo Log 是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版 ...