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 ...
随机推荐
- winMTR的使用
WinMTR下载链接:http://pan.baidu.com/share/link?shareid=236531&uk=1126982975 WinMTR 使用方法及软件介绍: WinMTR ...
- 对路径 obj 文件夹访问被拒绝
TFS 刚下载的项目,出现该问题. 解决方案: 将文件夹属性“只读”,取消
- Oracle取查询结果数据的第一条记录SQL
Oracle取查询结果数据的第一条记录SQL: ; ;
- ora-20000 unable to analyze
ora-20000 unable to analyze 无法分析表 check: select * from wmsprdata.cmp3$88278表不存在. result:应该是系统自动任务2:0 ...
- CF817B Makes And The Product
思路: 模拟,数学. 实现: #include <iostream> #include <cstdio> #include <algorithm> using na ...
- magento category Ids Name
如何获取产品的分类的名称 和ids 1.对于产品的分类ids 的获取 $this->getProduct()->getCategoryIds() 2.对应产品的分类的Name 的 ...
- Ps 快捷键全解
一.工具箱(多种工具共用一个快捷键的可同时按[Shift]加此快捷键选取)矩形.椭圆选框工具 [M]移动工具 [V]套索.多边形套索.磁性套索 [L]魔棒工具 [W]裁剪工具 [C]切片工具.切片选择 ...
- RabbitMQ调用
添加 gradle依赖complie("com.rabbitmq:amqp-client:5.0.0") Hello, World Working Queues Publish/S ...
- CNN结构:可用于时序预测复合的DNN结构-AcGANs、误差编码网络 ENN
前言:模式识别问题 模式函数是一个从问题定义域到模式值域的一个单射. 从简单的贝叶斯方法,到只能支持二分类的原始支持向量机,到十几个类的分类上最好用的随机森林方法,到可以支持ImageNet上海量18 ...
- 模拟title提示!
转载http://wouit.com/post/2013-08-15/40052169981html <a href="#" tishi="常见的网页新闻循环跳动显 ...