RxJava如何结合观察者与链式处理

Author: Dorae

Date: 2018年12月3日17:10:31

转载请注明出处


一、概述

首先问自己几个问题,如果非常清楚这几个问题的目的与答案,那么恭喜你,不用继续往下看了-_-。

  1. RxJava是干什么的;
  2. 链式调用中当存在数个Observable.subscribeOn()时的处理方式;
  3. 链式调用中当存在数个Observable.observeOn()时的处理方式;
  4. 数据是如何经过操作符进行的处理。

回顾

观察者模式

如图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(一)基本流程源码分析

RxJava基本原理分析

RxJava如何结合观察者与链式处理的更多相关文章

  1. PHP设计模式:类自动载入、PSR-0规范、链式操作、11种面向对象设计模式实现和使用、OOP的基本原则和自动加载配置

    一.类自动载入 SPL函数 (standard php librarys) 类自动载入,尽管 __autoload() 函数也能自动加载类和接口,但更建议使用 spl_autoload_registe ...

  2. 用php实现一个简单的链式操作

    最近在读<php核心技术与最佳实践>这本书,书中第一章提到用__call()方法可以实现一个简单的字符串链式操作,比如,下面这个过滤字符串然后再求长度的操作,一般要这么写: strlen( ...

  3. C#用链式方法表达循环嵌套

    情节故事得有情节,不喜欢情节的朋友可看第1版代码,然后直接跳至“三.想要链式写法” 一.起缘 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中单,上单,ADC,辅助:第二局新 ...

  4. 由表单验证说起,关于在C#中尝试链式编程的实践

    在web开发中必不可少的会遇到表单验证的问题,为避免数据在写入到数据库时出现异常,一般比较安全的做法是前端会先做一次验证,通过后把数据提交到后端再验证一次,因为仅仅靠前端验证是不安全的,有太多的htt ...

  5. 如何写 JS 的链式调用 ---》JS 设计模式《----方法的链式调用

    1.以$ 函数为例.通常返回一个HTML元素或一个元素集合. 代码如下: function $(){ var elements = []; ;i<arguments.length;i++){ v ...

  6. iOS 链式编程探索(Masonry)

    看了几篇关于链式编程的文章,还是理解的不透彻,我想这可能是因为我自己对block掌握的不熟练. 我已经明白了,所以,和大家分享一下我的理解!如有问题,麻烦大家指出! 直接看代码吧!关键的注释都有. 我 ...

  7. jQuery插件编写及链式编程模型小结

    JQuery极大的提高了我们编写JavaScript的效率,让我们可以愉快的编写代码,做出各种特效.大多数情况下,我们都是使用别人开发的JQuery插件,今天我们就来看看如何把我们常用的功能做出JQu ...

  8. ASP.NET MVC学前篇之扩展方法、链式编程

    ASP.NET MVC学前篇之扩展方法.链式编程 前言 目的没有别的,就是介绍几点在ASP.NETMVC 用到C#语言特性,还有一些其他琐碎的知识点,强行的划分一个范围的话,只能说都跟MVC有关,有的 ...

  9. 原生JS实现jquery的链式编程。

    这是我根据之前遇到的一个面试题,题目:用原生JS实现$("#ct").on("click",fn).attr("id"). 然后看了篇jqu ...

随机推荐

  1. MvcPager 分页控件

    官方教程: http://www.webdiyer.com/mvcpager

  2. Html 标签的事件绑定(转自 MSDN)

    参考 MSDN 网页给 HTML 标签绑定 click 事件: function makeFoldersCollapsible(folderIcon, openFolderIcon, pathToIc ...

  3. cocos creator 场景如何透明,多个canvas层级显示

    转载地址:https://forum.cocos.com/t/creator-canvas/55373/14 Creator 版本:1.7 目标平台:WEB MOBILE 项目需要,页面做了多个Can ...

  4. [转]TFS下的源代码控制

    本文转自:http://www.cnblogs.com/ajiefj/archive/2010/04/23/1718450.html 以下主要描述了: TFS源代码控制系统的基本场景 如何把一个项目添 ...

  5. PS技巧汇总

    一.gif图流程 1:素材图片a  图片b 2:窗口--->时间轴/动画 3:复制所选帧--->设置帧延迟 4:文件--->存储为WEB格式--->gif格式 二.批处理--- ...

  6. md5加密、Des加密对称可逆加密、RSA非对称可逆加密、https单边验证、银行U盾双边认证

    1.md5不可逆的加密方式,加密成一个32位的字符串.算法是公开的,任何语言的加密结果都是一样的.总有可能是重复的.     用途:             (1)防止明文存储:可以用作密码加密    ...

  7. 全志A33平台编译linux(分色排版)sina33

    全志A33平台编译linux 大文实验室/大文哥 壹捌陆捌零陆捌捌陆捌贰 21504965 AT qq.com 完成时间:2017/12/12 17:36 版本:V1.0 Xshell 5 (Buil ...

  8. Ionic2/angularJs2中的静态类 PhotoLibrary 调用不上

    photoLibrary调用报错:No provider for PhotoLibrary: 在调用相册文件时有用到photolibrary,总有些莫名的报错,3月份的时候这个坑让我不知所措,现在写下 ...

  9. Android yuv转Bitmap

      YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null); if(image!=nu ...

  10. C++11:using 的各种作用

    C++11中using关键字的主要作用是:为一个模板库定义一个别名. 文章链接:派生类中使用using别名改变基类成员的访问权限  一.<Effective Modern C++>里有比较 ...