Rxjava observeOn()和subscribeOn()初探
Rxjava这么强大的类库怎么可能没有多线程切换呢?
其中observeOn()与subscribeOn()就是实现这样的作用的。本文主要讲解observeOn()与subscribeOn()的用法,不去探究其中的原理。
0. 默认情况
在默认情况下,其不做任何线程处理,Observable和Observer处于同一线程,没有做任何线程切换,依次执行,如下图所示:

可以写一个demo测试之:
Observable<String> source = Observable.just("Alpha","Beta","Gamma");
source.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.i("TAG", "Received " + integer + " on thread:" +
Thread.currentThread().getName());
}
});
1. subscribeOn()的作用
该方法是指明数据产生的线程,即Observable发射数据所在的线程,如果之后不做任何处理,操作符operator(如map,flatmap等)也在subscribeOn指定的线程做数据处理。

多次使用subscribeOn()并不能频繁地切换线程,只有距离数据源最近的一个subscribeOn()唯一确定数据源发射数据的线程。如代码所示:
Observable<String> source = Observable.just("Alpha","Beta","Gamma");
source
.subscribeOn(Schedulers.computation())
.subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
}
});
}
其中只有subscribeOn(Schedulers.computation())对数据源source起作用,该source在Schedulers.computation()指定的线程发射数据。如果后面没有使用observeOn(),操作符operator都会在Schedulers.computation()所指定的线程做数据变换。
2. observeOn()的作用
在Android开发中,我们经常面临这样的场景,在工作者线程中产生数据,在UI线程中更新相应的View,subscribeOn()指定了数据发射的线程,但我们更新UI的操作,不可能在发射数据的线程运行,这会造成ANR的问题。此时就必须通过observeOn()方法做线程的切换:
Observable<String> source = Observable.just("Alpha","Beta","Gamma");
source.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
Log.i("TAG", "call: " + Thread.currentThread().getName());
return s.length();
}
}).observeOn(Schedulers.newThread()).subscribeOn(Schedulers.computation()).
subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
}
});
上述代码的运行结果如下:
TAG: call: RxComputationScheduler-1 TAG: onNext: on thread:RxNewThreadScheduler-1 TAG: call: RxComputationScheduler-1 TAG: onNext: on thread:RxNewThreadScheduler-1 TAG: call: RxComputationScheduler-1 TAG: onNext: on thread:RxNewThreadScheduler-1
可以看到,在observeOn()之前的操作,都运行在subscribeOn(Schedulers.computation())指定的线程,即RxComputationScheduler-1线程;而使用了observeOn()之后,在它之后的操作都
运行在了observeOn(Schedulers.newThread())指定的线程。
所以,给出一个结论observeOn()只对其之后的操作起作用;observeOn()可以使用多次,每次使用对其之后的operator起作用,对之前的操作没有影响。

上图很好地诠释了ObserveOn的作用。
3. backpressure的问题
由于ObserveOn的作用,数据流在多个线程中不断的传输,可能存在速度不匹配的情况。如下图所示,当底部的数据流发射速度快于顶部数据流的处理速度,若产生异常,可能导致一部分数据未被顶部的subscriber处理。

废话太多,说不清楚,看下代码吧:
Observable<String> source = Observable.just("Alpha","Beta","Gamma");
source.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
Log.i("TAG", "call: " + Thread.currentThread().getName());
if (s.equals("Gamma"))
throw new RuntimeException();
return s.length();
}
})
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.i("TAG", "doOnError: " + Thread.currentThread().getName());
}
})
.observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.computation())
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Log.i("TAG", "onError: " + "on thread:" + Thread.currentThread().getName());
}
@Override
public void onNext(Integer integer) {
Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
}
});
}
看一下运行结果:
TAG: call: RxComputationScheduler-1 TAG: call: RxComputationScheduler-1 TAG: call: RxComputationScheduler-1 TAG: doOnError: RxComputationScheduler-1 TAG: onError: on thread:RxNewThreadScheduler-1
我们就可以看到,当发射的数据为Gamma时抛出异常,之前发射的数据"Alpha","Beta"还未被subsriber的onNext方法处理,这就是backpressure问题。
4. onErrorResumeNext
onErrorResumeNext是错误恢复处理方法,当我们数据链中某个操作符抛出异常,此时会中断整个数据链,但我们想尝试恢复一下,这时可以使用
onErrorResumeNext。比如Android在过于频繁登录时,系统会弹出一个dialog(弹窗),让用户输入验证码,该逻辑就可以放在onErrorResumeNext中处理。
我们先看一段代码:
Observable<String> source = Observable.just("Alpha","Beta","Gamma");
source.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
Log.i("TAG", "call: " + Thread.currentThread().getName());
if (s.equals("Gamma"))
throw new RuntimeException();
return s.length();
}
})
.observeOn(Schedulers.newThread())
.subscribeOn(Schedulers.computation())
.onErrorResumeNext(new Func1<Throwable, Observable<? extends Integer>>() {
@Override
public Observable<? extends Integer> call(Throwable throwable) {
return Observable.just(1000).map(new Func1<Integer, Integer>() {
@Override
public Integer call(Integer integer) {
Log.i("TAG", "call:onErrorResumeNext: " + Thread.currentThread().getName());
return integer;
}
})
.subscribeOn(Schedulers.computation());
}
})
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
Log.i("TAG", "onError: " + "on thread:" + Thread.currentThread().getName());
}
@Override
public void onNext(Integer integer) {
Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
}
});
看上段代码中标红的部分,为什么在onErrorResumeNext可以再次使用subscribeOn(),我的猜测(并没有看源码)可能是该段代码产生了新的数据源,所以可以使用subsribeOn()指定数据源发射数据的线程。
它的运行结果:
TAG: call: RxComputationScheduler-1 TAG: call: RxComputationScheduler-1 TAG: call: RxComputationScheduler-1 TAG: onNext: on thread:RxNewThreadScheduler-1 TAG: onNext: on thread:RxNewThreadScheduler-1 TAG: call:onErrorResumeNext: RxComputationScheduler-2 TAG: onNext: on thread:RxComputationScheduler-2
看运行结果在onErrorResumeNext方法中使用了subscribeOn(),线程切换到了RxComputationScheduler-2,在之后没有observeOn的情况下,最后一个onNext也运行在了RxComputationScheduler-2。很神奇!!!!!
Rxjava observeOn()和subscribeOn()初探的更多相关文章
- RxJava尝试取代Handler初探
在之前的一篇文章中,我们探究了RxJava的使用方法,详细请看https://www.cnblogs.com/yanyojun/p/9745675.html 根据扔物线大神的描述,如果用一个词来概括R ...
- 78. Android之 RxJava 详解
转载:http://gank.io/post/560e15be2dca930e00da1083 前言 我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Fli ...
- 给 Android 开发者的 RxJava 详解
我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个 ...
- 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库 RxJava,相当好
https://github.com/ReactiveX/RxJava https://github.com/ReactiveX/RxAndroid RX (Reactive Extensions,响 ...
- RxJava开发精要7 – Schedulers-解决Android主线程问题
原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...
- RxJava系列6(从微观角度解读RxJava源码)
RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...
- RxJava(11-线程调度Scheduler)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51821940 本文出自:[openXu的博客] 目录: 使用示例 subscribeOn原理 ...
- 理解 RxJava 的线程模型
来源:鸟窝, colobu.com/2016/07/25/understanding-rxjava-thread-model/ 如有好文章投稿,请点击 → 这里了解详情 ReactiveX是React ...
- android ------- 开发者的 RxJava 详解
在正文开始之前的最后,放上 GitHub 链接和引入依赖的 gradle 代码: Github: https://github.com/ReactiveX/RxJava https://github. ...
随机推荐
- 2017携程Web前端实习生招聘笔试题总结
考察encodeURI encodeURI(), decodeURI()它们都是Global对象的方法. encodeURI()通过将某些字符的每个实例替换代表字符的UTF-8编码的一个或多个转义字符 ...
- java上转型和下转型(对象的多态性)
/*上转型和下转型(对象的多态性) *上转型:是子类对象由父类引用,格式:parent p=new son *也就是说,想要上转型的前提必须是有继承关系的两个类. *在调用方法的时候,上转型对象只能调 ...
- 深入浅出学习HTTP协议
之前学习javaWeb只是大致了解了一下,今天重点介绍下http请求,当是复习吧! 一.http基础概念 1.什么是http协议? HTTP是Hyper Text Transfer Protocol( ...
- Java中的多线程Demo
一.关于Java多线程中的一些概念 1.1 线程基本概念 从JDK1.5开始,Java提供了3中方式来创建.启动多线程: 方式一(不推荐).通过继承Thread类来创建线程类,重写run()方法作为线 ...
- css3隐藏导航栏总结
display:none隐藏display:block显示 1.通过hover显示时隐藏元素必须与触发元素存在着关系(父子,兄弟)才能生效,所以推荐用JS完成比较好. 2.隐藏部分的属性直接写在hov ...
- 最大流算法之ISAP
序: 在之前的博文中,我解释了关于最大流的EK与Dinic算法,以及它们的STL/非STL的实现(其实没什么区别).本次讲解的是ISAP算法.'I',指 inproved,也就是说ISAP其实是SAP ...
- Cygwin Unable to get setup from *
Cygwin Unable to get setup from * 错误 解决方案 是因为用自定义镜像站点,比如 http://mirrors.xdlinux.info/cygwin/x86_64/ ...
- 配置网络yum源
有的时候服务器需要下载一些软件,是本地yum源没有的,这时候需要配置网络yum源 #cd /etc/yum.repos.d/ 把这个目录下的配置文件备份,改名:或者是把文件里边的enabled=1的 ...
- jt格式文件与网格压缩
jt格式文件与网格压缩 介绍 jt是一种3D数据格式,主要用于工业,产品可视化,数据交换,并且西门子在2012推动jt成为ISO国际标准.在文件尺寸方面,采用了不少专门的压缩方法,比较轻量化. jt文 ...
- Samba文件共享服务
Samba起源: 早期网络想要在不同主机之间共享文件大多要用FTP协议来传输,但FTP协议仅能做到传输文件却不能直接修改对方主机的资料数据,这样确实不太方便,于是便出现了NFS开源文件共享程序:NFS ...