那么本文就将对Rxjava做一次详细的探索,相信跟随着博主的思路带着自己的思考,你一定也能掌握使用这个热门技术的要领。不仅如此,我们更要深入了解其内部原理,做到知其然,并且知其所以然。
关于Rxjava的基本了解以及其使用,我在该系列的另一篇文章中已经介绍过了。详情关注
RxJava 2.x 教程及源码揭秘(一)入门理解及应用
在另一篇文章中,从源码出发,了解了其内部流程,理解Rxjava是如何实现线程的切换以及对任务逻辑的一些加工,并保持其链式结构
RxJava 2.x 教程及源码揭秘(三)Rxjava操作符源码解析
本文将从设计模式的角度,带你完整地回顾一下RxJava整个流程中一些重要的点,让你彻底了解这个流行的工具库的内部原理
采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。举个安卓中最典型的例子吧,我们空间的点击事件监听就是一种观察者模式,对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。
采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。
我们来对比下OnclickListener和RxJava
Buton持有OnClickListener的引用,当Button触发了点击事件,调用OnClickListene的OnClik方法,这就是观察者的流程,相信集合上面图片的对比,你已经知道了RxJava中各部分分别对应的角色。
RxJava 有四个基本概念:Observable
(可观察者,即被观察者)、 Observer
(观察者)、 subscribe
(订阅)、事件。Observable
和 Observer
通过 subscribe()
方法实现订阅关系,从而 Observable
可以在需要的时候发出事件来通知 Observer
。
RxJava所有操作符的共同原理:lift()
这些变换虽然功能各有不同,但实质上都是针对事件序列的处理和再发送。而在 RxJava 的内部,它们是基于同一个基础的变换方法: lift(Operator)
。首先看一下 lift()
的内部实现(仅核心代码):
// 注意:这不是 lift() 的源码,而是将源码中与性能、兼容性、扩展性有关的代码剔除后的核心代码。
// 如果需要看源码,可以去 RxJava 的 GitHub 仓库下载。
public Observable lift(Operator extends R, ? super T> operator) {
return Observable.create(new OnSubscribe() {
@Override
public void call(Subscriber subscriber) {
Subscriber newSubscriber = operator.call(subscriber);
newSubscriber.onStart();
onSubscribe.call(newSubscriber);
}
});
}
这段代码很有意思:它生成了一个新的 Observable
并返回,而且创建新 Observable
所用的参数 OnSubscribe
的回调方法 call()
中的实现竟然看起来和前面讲过的 Observable.subscribe()
一样!然而它们并不一样哟~不一样的地方关键就在于第二行 onSubscribe.call(subscriber)
中的 onSubscribe
所指代的对象不同(高能预警:接下来的几句话可能会导致身体的严重不适)——subscribe()
中这句话的 onSubscribe
指的是 Observable
中的 onSubscribe
对象,这个没有问题,但是 lift()
之后的情况就复杂了点。当含有 lift()
时: 1.lift()
创建了一个 Observable
后,加上之前的原始 Observable
,已经有两个 Observable
了;
2.而同样地,新 Observable
里的新 OnSubscribe
加上之前的原始 Observable
中的原始 OnSubscribe
,也就有了两个 OnSubscribe
3.当用户调用经过 lift()
后的 Observable
的 subscribe()
的时候,使用的是 lift()
所返回的新的 Observable
,于是它所触发的 onSubscribe.call(subscriber)
,也是用的新 Observable
中的新 OnSubscribe
,即在 lift()
中生成的那个 OnSubscribe
;
4.而这个新 OnSubscribe
的 call()
方法中的 onSubscribe
,就是指的原始 Observable
中的原始 OnSubscribe
,在这个 call()
方法里,新 OnSubscribe
利用 operator.call(subscriber)
生成了一个新的 Subscriber
(Operator
就是在这里,通过自己的 call()
方法将新 Subscriber
和原始 Subscriber
进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新 Subscriber
向原始 Observable
进行订阅。
这样就实现了 lift()
过程,有点像一种代理机制,通过事件拦截和处理实现事件序列的变换。
精简掉细节的话,也可以这么说:在 Observable
执行了 lift(Operator)
方法之后,会返回一个新的 Observable
,这个新的 Observable
会像一个代理一样,负责接收原始的 Observable
发出的事件,并在处理后发送给 Subscriber
。
如果你更喜欢具象思维,可以看图:
或者可以看动图:
两次和多次的 lift()
同理,如下图:
subscribeOn()
和 observeOn()
的内部实现,也是用的 lift()
。具体看图(不同颜色的箭头表示不同的线程):
subscribeOn()
原理图:
observeOn()
原理图:
从图中可以看出,subscribeOn()
和 observeOn()
都做了线程切换的工作(图中的 "schedule..." 部位)。不同的是, subscribeOn()
的线程切换发生在 OnSubscribe
中,即在它通知上一级 OnSubscribe
时,这时事件还没有开始发送,因此 subscribeOn()
的线程控制可以从事件发出的开端就造成影响;而 observeOn()
的线程切换则发生在它内建的 Subscriber
中,即发生在它即将给下一级 Subscriber
发送事件时,因此 observeOn()
控制的是它后面的线程。
最后,我用一张图来解释当多个 subscribeOn()
和 observeOn()
混合使用时,线程调度是怎么发生的(由于图中对象较多,相对于上面的图对结构做了一些简化调整):
为什么subscribeOn()
进行了接收线程的切换,发射线程仅仅响应了第一个 newThread
,但每调用一次 observeOn()
,线程便会切换一次。subscribeOn()
的位置放在哪里都可以,但它是只能调用一次的。
我们来了解一下其订阅与数据传递的流程
订阅过程:从下往上
1.终点Observer订阅了map返回的ObserableMap。
2.map的Observable(ObservableMap)被订阅时,会订阅其上游的Observable,用于订阅上游的Observer是一个装饰者(MapObserver),内部保存了下游Observer,上游发数据时,传递给下游。
3.以此类推,源头Observable被订阅时,他会向Observer发数据
数据传递过程:从上往下
1.源头Observable传递数据给下游Observer
2.Observer收到数据对其变换的操作之后(就是Function执行之后),在调用内部保存的下游Observer的onNext()发送数据给下游
3.以此类推,最终把数据送达至终点Observer
通过对这两个流程的理解,你会发现,订阅是从下往上,所以第一个subscribeOn()
最后被调用,所以无论你调用多少次,只响应第一个。同理,数据的发送是自上而下的,最下面,就是最后一个observeOn()
被调用被最后调用,所以无论你调用多少次,都会响应最后一次;