上一篇文章Android进阶:四、RxJava2 源码解析 1里我们讲到Rxjava2

从创建一个事件到事件被观察的过程原理,这篇文章我们讲Rxjava2中链式调用的原理。本文不讲用法,仍然需要读者熟悉Rxjava基本的用法。

一.Rxjava2 的基本用法

Rxjava是解决异步问题的,它的链式调用让代码看起来非常流畅优雅。现在我们带上线程切换以及链式调用来看看。下面代码是示例:

  1. Observable
  2. .create(new ObservableOnSubscribe<String>() {
  3. @Override
  4. public void subscribe(ObservableEmitter<String> e) throws Exception {
  5. e.onNext("a");
  6. }
  7. })
  8. .subscribeOn(Schedulers.io())
  9. .unsubscribeOn(Schedulers.io())
  10. .observeOn(AndroidSchedulers.mainThread())
  11. .map(new Function<String, Integer>() {
  12. @Override
  13. public Integer apply(String s) throws Exception {
  14. return 1;
  15. }
  16. })
  17. .subscribe(new Observer<Object>() {
  18. @Override
  19. public void onSubscribe(Disposable d) {
  20. }
  21. @Override
  22. public void onNext(Object o) {
  23. }
  24. @Override
  25. public void onError(Throwable e) {
  26. }
  27. @Override
  28. public void onComplete() {
  29. }
  30. });

我们创建一个事件(观察者),想输出一个字符串 “a”。这个事件发生在IO线程,结束也在IO线程,事件的状态回调发生在主线程。示例的用法大家应该都能懂,我们主要讨论这个链式的原理流程。为什么这么说呢?因为这个链式跟一般的链式不太一样。

二.create方法

这个方法我们之前看过,返回一个ObservableCreate对象,ObservableCreate继承自Observable,里面的source存着我们创建的ObservableOnSubscribe匿名对象。

三.subscribeOn方法

这是Obserbvable的方法,先看源码:

  1. public final Observable<T> subscribeOn(Scheduler scheduler) {
  2. ObjectHelper.requireNonNull(scheduler, "scheduler is null");
  3. return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
  4. }
  5. public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
  6. Function<? super Observable, ? extends Observable> f = onObservableAssembly;
  7. if (f != null) {
  8. return apply(f, source);
  9. }
  10. return source;
  11. }

代码结构跟create的差不多,在钩子函数里直接返回我们创建的对象ObservableSubscribeOn(this, scheduler),并传入当前的Observable也就是ObservableCreate对象。所以我们看一下这个类的代码:

  1. public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
  2. final Scheduler scheduler;
  3. public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
  4. super(source);
  5. this.scheduler = scheduler;
  6. }
  7. }

这个类继承自AbstractObservableWithUpstream类,构造函数的参数是ObservableSource,所以这里我们需要介绍两个类:

  • ObservableSource

    ObservableSource是一个接口,所有的Observable都实现了这个接口,它里面只有:
  1. void subscribe(@NonNull Observer<? super T> observer);

这一个方法。很明显这个方法是为了让Observer订阅Observable的,或者说为了Observable把事件状态传递给Observer的。

  • AbstractObservableWithUpstream

    这个类继承了Observbable
  1. abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> {
  2. protected final ObservableSource<T> source;
  3. AbstractObservableWithUpstream(ObservableSource<T> source) {
  4. this.source = source;
  5. }
  6. }

从源码可以看出这个类有变量source,它在构造函数里传入值,存储ObservableSource对象。

所以当我们调用Observable的subscribeOn方法的时候会创建一个ObservableSubscribeOn对象,并用变量source存储当前的Observable对象,然后返回ObservableSubscribeOn对象。

四.unsubscribeOn方法

  1. public final Observable<T> unsubscribeOn(Scheduler scheduler) {
  2. ObjectHelper.requireNonNull(scheduler, "scheduler is null");
  3. return RxJavaPlugins.onAssembly(new ObservableUnsubscribeOn<T>(this, scheduler));
  4. }
  5. public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
  6. Function<? super Observable, ? extends Observable> f = onObservableAssembly;
  7. if (f != null) {
  8. return apply(f, source);
  9. }
  10. return source;
  11. }

这个方法跟上面的方法是一个模子刻的。所以我们主要看ObservableUnsubscribeOn这个类就好。

  1. public final class ObservableUnsubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
  2. final Scheduler scheduler;
  3. public ObservableUnsubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
  4. super(source);
  5. this.scheduler = scheduler;
  6. }
  7. }

这个类跟刚才的ObservableSubscribeOn也几乎一模一样,继承自AbstractObservableWithUpstream类,使用source存了当前Observable对象。而此时的Observbvable对象是上一个方法创建的对象,也就是ObservableSubscribeOn对象。

五.observeOn方法和map方法

由于这些方法的内容基本一样我就省略代码的解释。

observeOn方法是创建了ObservableObserveOn对象,并保存上一个方法创建的Observable。map方法是创建ObservableMap对象,并保存上一个方法创建的Observable

所以总结一下可知:链式调用这些方法的时候,都会创建一个相关的对象,然后用变量source存储上一个方法创建的Observable子类对象。

六.subscribe方法

上次文章讲到,这个方法内部会调用一个抽象方法,subscribeActual方法,作为真实的订阅。而这个方法的逻辑需要看子类如何实现。

而第一次调用该这个subscribe方法的对象是ObservableMap对象。所以我们看看它内部如何实现的。

ObservableMap的subscribeActual方法实现:

  1. public void subscribeActual(Observer<? super U> t) {
  2. source.subscribe(new MapObserver<T, U>(t, function));
  3. }

内部调用了source的subscribe方法。此时ObservableMap对象里存的source是上一个方法创建的observable,也就是ObservableObserveOn对象。所以我们要看看ObservableObserveOn是如何实现subscribeActual方法的:

  1. protected void subscribeActual(Observer<? super T> observer) {
  2. if (scheduler instanceof TrampolineScheduler) {
  3. source.subscribe(observer);
  4. } else {
  5. Scheduler.Worker w = scheduler.createWorker();
  6. source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
  7. }
  8. }

同理他最终也是调用了上一个Observable的subscribe。

于是我们知道当我们调用subscribe方法的时候,会递归式的调用source存储的上一个方法创建的Observable的subscribeActual方法,一直到ObsservableCreate的subscribeActual的方法,把事件状态传递给观察者。这个上一篇文章已经讲过。

七.总结

我们常见的普通的链式调用一般都会返回当前同一个对象。和普通的链式调用不同当我们调用Rxjava2的链式调用时,他们会返回自己对应的Observable子类对象,每个对象都不一样,然后在subscribeActual方法中递归式的调用每个对象的subscribeActual方法,完成一个链式的调用。

Android进阶:五、RxJava2源码解析 2的更多相关文章

  1. RxJava2 源码解析(二)

    概述 承接上一篇RxJava2 源码解析(一),本系列我们的目的: 知道源头(Observable)是如何将数据发送出去的.    知道终点(Observer)是如何接收到数据的.    何时将源头和 ...

  2. RxJava2源码解析(二)

    title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...

  3. Android进阶:四、RxJava2 源码解析 1

    本文适合使用过Rxjava2或者了解Rxjava2的基本用法的同学阅读 一.Rxjava是什么 Rxjava在GitHub 主页上的自我介绍是 "a library for composin ...

  4. Git8.3k星,十万字Android主流开源框架源码解析,必须盘

    为什么读源码 很多人一定和我一样的感受:源码在工作中有用吗?用处大吗?很长一段时间内我也有这样的疑问,认为哪些有事没事扯源码的人就是在装,只是为了提高他们的逼格而已. 那为什么我还要读源码呢?一刚开始 ...

  5. 多线程与高并发(五)—— 源码解析 ReentrantLock

    一.前言 ReentrantLock 是基于 AQS 实现的同步框架,关于 AQS 的源码在 这篇文章 已经讲解过,ReentrantLock 的主要实现都依赖AQS,因此在阅读本文前应该先了解 AQ ...

  6. RxJava2 源码解析(一)

    概述 最近事情太多了,现在公司内部的变动,自己岗位的变化,以及最近决定找工作.所以博客耽误了,准备面试中,打算看一看RxJava2的源码,遂有了这篇文章. 不会对RxJava2的源码逐字逐句的阅读,只 ...

  7. Android构建工具--AAPT2源码解析(一)

    一.什么是AAPT2 在Android开发过程中,我们通过Gradle命令,启动一个构建任务,最终会生成构建产物"APK"文件.常规APK的构建流程如下: (引用自Google官方 ...

  8. Android进阶系列之源码分析Activity的启动流程

    美女镇楼,辟邪! 源码,是一个程序猿前进路上一个大的而又不得不去翻越障碍,我讨厌源码,看着一大堆.5000多行,要看完得啥时候去了啊.不过做安卓的总有这一天,自从踏上这条不归路,我就认命了.好吧,我慢 ...

  9. 【Android】IntentService & HandlerThread源码解析

    一.前言 在学习Service的时候,我们一定会知道IntentService:官方文档不止一次强调,Service本身是运行在主线程中的(详见:[Android]Service),而主线程中是不适合 ...

随机推荐

  1. 常用Hadoop命令(bin)

    **** bin 是二进制文件的意思,sbin....据说是superbin(管理员的bin) HDFS命令 某个文件的blocks信息 hadoop fsck /user/xx -files -bl ...

  2. 编译VisualVM源码解决乱码问题

    编译VisualVM源码解决乱码问题 起因 今天在使用VisualVM对测试服务器进行JVM监控的时候,发现所有统计图的横纵坐标都是显示乱码(小方块),即使我的Ubuntu系统使用的是英文语言环境.奇 ...

  3. 神奇的 UNICODE 字符 : U+202E

  4. html常用标签的取值和赋值操作

    我们在html页面当中,面对各种各样的标签,经常需要处理取值和赋值的问题,下面,就把常见的一些html标签元素的取值和赋值操作进行总结整理,以后备用. 1.button:改变button按钮上面的值, ...

  5. antd table 点击行触发radio 或 checkbox

     UIStore.ts (使用mobx) 1 import { observable, action, computed } from 'mobx' export class UIStore { @o ...

  6. winform 以不规则图形背景显示窗体

    一:创建一个winform窗体,把BackgroundImage引入一个不规则的图片,设置属性BackgroundImageLayout为Stretch 二:主要代码 using System; us ...

  7. Ansible-----include

    什么是include 在ansible中,我们可以通过include,在一个playbook中包含另一个文件,以便实现代码的重复利用. include_tasks模块 include_tasks模块用 ...

  8. “放到桌面”的Servlet实现

    复习下Servlet下载文件, 当response把ContentType设置成application/xxxx的时候呢,浏览器会默认启动下载,而不是试图打开. 通过给httpHeader里面加入内容 ...

  9. 【转】Python3—UnicodeEncodeError 'ascii' codec can't encode characters in position 0-1

    转自:https://blog.csdn.net/AckClinkz/article/details/78538462 环境 >>> import sys >>> ...

  10. [Linux]信号集和sigprocmask信号屏蔽函数

    一.概述 系统提供这样一种能力,就是创建一个信号集,然后传递给信号屏蔽函数,从而屏蔽向该进程发送的信号. 有一点需要注意的是,不能屏蔽SIGKILL和SIGSTOP信号. 信号集是sigset_t类型 ...