RxJava如何结合观察者与链式处理
RxJava如何结合观察者与链式处理
Author: Dorae
Date: 2018年12月3日17:10:31
转载请注明出处
一、概述
首先问自己几个问题,如果非常清楚这几个问题的目的与答案,那么恭喜你,不用继续往下看了-_-。
- RxJava是干什么的;
- 链式调用中当存在数个Observable.subscribeOn()时的处理方式;
- 链式调用中当存在数个Observable.observeOn()时的处理方式;
- 数据是如何经过操作符进行的处理。
回顾
观察者模式
如图1-1所示

图 1-1
Java8的stream
二、RxJava是什么
一款为了简化异步调用,且功能比较全面的框架。
三、RxJava如何结合了观察者模式与链式处理
参见Java8中的sink链,在RxJava中同样实现了链式处理。如代码片段code1-1所示,我们对其结构进行分析:
code1-1
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("Dorae");
}
})
.filter(e -> e.contains("o"))
.map(e -> "AfterMap: " + e)
.filter(e -> e.contains("D"))
.subscribe(new Observer<String>() {
@Override
public void onNext(@NonNull String o) {
System.out.println("观察者 onNext: " + o);
}
@Override
public void onSubscribe(Disposable d) {
System.out.println("观察者onSubscribe: " + d + "### " + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
1、首先看下其输出结果:
观察者onSubscribe: io.reactivex.internal.operators.observable.ObservableFilter$FilterObserver@52d455b8### main
观察者 onNext: AfterMap: Dorae
2、现在来对如何输出这段结果进行分析
首先了解下RxJava中的几种基本角色:
- Observable,是RxJava描述的事件流,可以说其与Observer构成了RxJava的基础。在链式调用中,事件从创建到加工到最后被Observer接受,其实就是由一条Observerable链串起来的。
- Observer,RxJava中的订阅者,也就是需要对事件进行响应的一个角色。其实除了我们通常自己实现的一个Observer,在链中的每一步都会产生一个Observer,然后这些Observer构成一条链,最终完成整个链的计算。
- ObservableOnSubscribe,整个事件流的源头,通常需要我们自己实现,其依赖一个Emitter。
- Emitter,可以将其理解为触发器,推动整个流程的运转。
- Scheduler,这个其实不用太过关心,RxJava用其封装了Thread,用于完成线程切换等任务。
是不是感觉上边的一堆废话非常枯燥?先上一张RxJava的核心结构,如图3-1所示。

图 3-1
现在我们再来看看code1-1,其最终形成的Observable链如图3-2所示,每次调用map、filter等操作,都会生成一个新对象,并且保持了一个对上游的引用(用于生成Observer链)。

图 3-2
Observer链如图3-3所示,整个事件流程由CreateEmitter触发,最终交由我们的实现Observer$1处理。

图 3-3
看了上边几张图之后,是不是感觉清晰了很多?那么让我们进一步看下Rxjava如何完成了一键线程切换。
四、RxJava如何实现线程切换
通常我们使用RxJava的线程切换功能时,只需要在调用链中加上一句subscribeOn()或observeOn(),其中Scheduler如上所述,其实就是一个包装了ThreadPool的调度器。那么我们先来看下相关源码。
1、subscribeOn
如代码code4-1所示,为subscribeOn的核心代码。很明显,其中在新线程中只是简单的直接调用了source,也就是说这里之后的所有操作均在一个新线程中进行,和单线程并没有什么区别。
code 4-1
public final Observable<T> subscribeOn(Scheduler scheduler) {
return new ObservableSubscribeOn<T>() {
@Override
public void subscribeActual(final Observer<? super T> observer) {
scheduler.createWorker().schedule(new SubscribeTask() {
@Override
public void run() {
source.subscribe(e);
}
});
}
};
}
2、observeOn
如代码段code4-2所示,为observeOn的核心逻辑,可以看出其在订阅阶段(生成Observer链的阶段)还是在当前线程执行,只有触发之后,到了ObserverOn的Observer的节点时才会真正的切换到新线程。
code 4-2
public final Observable<T> observeOn(Scheduler scheduler) {
return new ObservableOnSubscribe<T>() {
@Override
public void subscribeActual(@NonNull Observer<Object> e) {
source.subscribe(new Observer<T>() {
@Override
public void onNext(T var1) {
scheduler.createWorker().schedule(new Runnable() {
@Override
public void run() {
e.onNext(var1);
}
});
}
});
}
};
}
多次Observable.subscribeOn()、多次Observable.observeOn()会发生什么
通过上述code4-1、code4-2的分析,是不是可以推断出当多次subscribeOn时会发生什么?没错,虽然每次subscribeOn都会产生一次线程切换,但是真正起作用的只有最开始的一次subscribeOn,也就相当于只在最初的位置调用了subscribeOn;对于observeOn也是类似,每次都会产生新线程,但是每次都会产生一定的影响,也就是每个线程都承担了一部分工作。
小结
通过本文,我们可以简要了解到RxJava的基本原理,但是对于其丰富的api还需要在实践中进行磨合。但是,RxJava既然作为一个异步框架,其必然有一定的局限,比如其切换线程时无法阻塞当前线程(这种对于Android等需要渲染或者网络IO的需求来说非常适用),但是对于常见的服务端业务来说,还需要额外引入阻塞当前线程的操作(因为大部分的server代码还是单线程模型),倘若完全不用线程切换在服务端强行引入,可能会得不偿失。个人更推荐Java8的CompletableFuture。
参考
RxJava如何结合观察者与链式处理的更多相关文章
- PHP设计模式:类自动载入、PSR-0规范、链式操作、11种面向对象设计模式实现和使用、OOP的基本原则和自动加载配置
一.类自动载入 SPL函数 (standard php librarys) 类自动载入,尽管 __autoload() 函数也能自动加载类和接口,但更建议使用 spl_autoload_registe ...
- 用php实现一个简单的链式操作
最近在读<php核心技术与最佳实践>这本书,书中第一章提到用__call()方法可以实现一个简单的字符串链式操作,比如,下面这个过滤字符串然后再求长度的操作,一般要这么写: strlen( ...
- C#用链式方法表达循环嵌套
情节故事得有情节,不喜欢情节的朋友可看第1版代码,然后直接跳至“三.想要链式写法” 一.起缘 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中单,上单,ADC,辅助:第二局新 ...
- 由表单验证说起,关于在C#中尝试链式编程的实践
在web开发中必不可少的会遇到表单验证的问题,为避免数据在写入到数据库时出现异常,一般比较安全的做法是前端会先做一次验证,通过后把数据提交到后端再验证一次,因为仅仅靠前端验证是不安全的,有太多的htt ...
- 如何写 JS 的链式调用 ---》JS 设计模式《----方法的链式调用
1.以$ 函数为例.通常返回一个HTML元素或一个元素集合. 代码如下: function $(){ var elements = []; ;i<arguments.length;i++){ v ...
- iOS 链式编程探索(Masonry)
看了几篇关于链式编程的文章,还是理解的不透彻,我想这可能是因为我自己对block掌握的不熟练. 我已经明白了,所以,和大家分享一下我的理解!如有问题,麻烦大家指出! 直接看代码吧!关键的注释都有. 我 ...
- jQuery插件编写及链式编程模型小结
JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我们就来看看如何把我们常用的功能做出JQu ...
- ASP.NET MVC学前篇之扩展方法、链式编程
ASP.NET MVC学前篇之扩展方法.链式编程 前言 目的没有别的,就是介绍几点在ASP.NETMVC 用到C#语言特性,还有一些其他琐碎的知识点,强行的划分一个范围的话,只能说都跟MVC有关,有的 ...
- 原生JS实现jquery的链式编程。
这是我根据之前遇到的一个面试题,题目:用原生JS实现$("#ct").on("click",fn).attr("id"). 然后看了篇jqu ...
随机推荐
- java io 读取写文件
java 读取txt文件,汉字乱码,原因是因为文件的编码格式和程序编码采用了不同的编码格式.通常,假如自己不修改的话,windows自身采用的编码格式是gbk(而gbk和gb2312基本上是一样的编码 ...
- 模拟 HDOJ 5387 Clock
题目传送门 /* 模拟:这题没啥好说的,把指针转成角度处理就行了,有两个注意点:结果化简且在0~180内:小时13点以后和1以后是一样的(24小时) 模拟题伤不起!计算公式在代码内(格式:hh/120 ...
- android序列化(2)Parcelable与Parcel
1.简介 Parcel : 包裹 Android采用这个它封装消息数据.这个是通过IBinder通信的消息的载体.需要明确的是Parcel用来存放数据的是内存(RAM),而不是永久性介质(Nand等 ...
- 解决Unicode编码(璘)
随着互联网发展,B/S越来越受欢迎 Code编码格式也越来载多, 在大千花花世界 中文在Web显示看似一样但实际编码并不样,导致从页面获取的资料录入到数据库中时 存取的就是Code编码 如:Unico ...
- iOS浏览器不能打开手机QQ客服与指定用户聊天界面
这个问题是我在公司需求的时候遇到的,QQ推广工具网站获取的链接在苹果自带浏览器没法打开到聊天界面,是因为safair在打开到app store的时候把参数给丢了,app store再打开到QQ的时候就 ...
- 如何取消android studio启动时自动打开上次关闭的项目
Androidstudio默认每次android studio启动就会自动打开上次关闭的项目,如果想要取消并让它显示此界面 只需要
- Selenium学习第二天,了解Selenium工作模式与学习Selenium需要具备的知识与工具。
Selenium学习网站: 1.http://www.ltesting.net/ceshi/open/kygncsgj/selenium/2014/0408/207237.html——好像是对API的 ...
- 使用libpqxx访问PostgreSQL数据库(mingw编译libpqxx)
编译前准备 1. 安装mingw 安装mingw(不管是直接安装mingw还是其他如code::blocks附带安装的mingw),输入:gcc -v可显示如下图的版本信息,我的版本是mingw ...
- Jmeter常用的逻辑控制器
一.ForEach控制器 作用:ForEach Controlle一般和用户自定义变量(User Defined Variables)一起使用,其在用户自定义变量中读取一系列相关的变量.每一个线程下执 ...
- Scrapy框架 之某网站产品采集案例
一.创建项目 第一步:scrapy startproject boyuan 第二步:cd boyuan scrapy genspider product -t crawl boyuan.com 如图 ...