前言:
今天刚刚给自己立了一个flag,那就是想抽空多写写自己对一些技术的理解,以书面的形式记录下来,这样会增加记忆
同时也方便自己查阅,当然最后如果可以能帮到一些有需要的人,那么就是我莫大的荣幸了。
首先咱也不好高骛远,仅当笔记使用,如有错误缺失,望能提议!
这里我先说一下自己分析源码的逻辑(毕竟是笔记,尽量以简洁为主,如有时间,再优化)
1:首先要知道它的功能是什么,如何利用它。
2:然后需要思考为什么使用它,也就是它的优点是什么。
3:最后就是带着2的疑问去看源码,这样我们才能得到自己想要的结果,不会盲目去看。
4:如果能力有限(比如我),那么看源码一定不要纠结于每一行的代码意思,有时可以直接去看方法注释,一些扩展类,优化类的方法,我们在初次探究的时候,其实不用费大力气去理解,毕竟我们想要了解的是它的架构思想,而非如何去实现,当然,如果能力卓越,将它整个分析出来那就更好了。
好了,言归正传,我们这篇就先讲讲Rxjava
本次分析主要基于Rxjava1.0,如果以后有时间,我也会更新一篇基于2.0的帖子。
Rxjava1.0 跟 Rxjava 2.0的区别主要是一些核心API的更改,还有对被压的友好支持。
文章目录
Rxjava的简介
1、概念及设计理念
Rxjava(Reactive Extensions for the JVM):
响应式扩展,用于java VM的可观察序列编写异步和基于事件的程序库
上面是官方提供的概念,有些抽象,但是我们可以从中获取到两个重要信息。
1、Rxjava的核心作用:异步
2、Rxjava的编程思想:响应式编程 和 观察者模式
异步我在这里先不讲,放到以后再说,毕竟它涉及到了Rxjava的另外一个核心作用变换(其实这么说并不严谨,毕竟Rxjava的异步实现其实也是基于变换的,但是为了让对Rxjava的理解有条理化,区分一下可能更合适一些)这里我们先提示一下,下面主要是先讲讲我对响应式编程的理解。
响应式编程:一种基于异步流数据的编程模式,其中有一个很重要的概念就是事件,而事件其实就是唯一可以用合适的方式将我们的现实世界映射到我们软件中的一种具现化表现。在响应式编程中,我们可以把事件或者事件序列比作一条河流中的鱼或者是一群鱼,它们可以被观测,被过滤,也可以被拦截,被捕获,甚至是可以在捕获之后做些处理后再放回河里,当然也可以流入到其它河流中。
2、Rxjava的优点及作用
Rxjava的优点我这里借用扔物线前辈博客中的几个词来概括:1、变换,2、简洁,3、异步。
也就是说Rxjava可以在我们需要异步或者变换的时候的让我们代码逻辑变得更加简洁,注意,这里说的是逻辑上面的的简洁。而非代码的简洁,它可以将一段很复杂的操作,变成一条链式调用,从头到尾逻辑清晰,容易梳理,提高可读性。
3、Rxjava的表现形式(观察者模式)
Rxjava的消息传递机制其实是采用了一种扩展的观察者模式来实现的,利用核心的几个API形成了一种观察者(Observer)(subscriber)订阅或者说监听被观察者(Observabler),然后被观察者(Observabler)利用接口(OnSubscriber)通知观察者(Observer)数据变化的接口回调机制,看起来可能有些绕,其实就是一个利用观察者模式搭建的事件回调框架,大家可以起先可以把它理解为一个简单的接口回调机制,如:Button, setOnClickLinstener ,onClickListener 三者之间的关系
API介绍和源码解析
1、核心API
1、通知接口(onSubscriber)
这里我把onSubscriber放在第一个来讲,主要就是因为在刚刚说说的那种订阅关系的产生时需要利用它来进行通知,它其实是一个接口,一个存在于Observabler中的接口,而起到的作用就是通知,当订阅关系成立的一瞬间通知被观察者,我们可以看下面的源码实现,内部就是传递了一个Observer的实例。
public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> { }
JAVA其实是一种面向对象的OOP变成语音,那么解决问题的复杂程度直接取决于抽象的种类及质量,所以这里我们思考一个抽象模型来概述RxJava的主要对象。
我们可以把它想象成现实生活中的 风向标,这里也是我想提醒大家大家一个需要注意的点,那就是前面我提到过它内部回调回来一个Observer的实例,那么在现实中我们其实可以把Observer的实例想象成在 风向标 上面包含有人注视的 目光(强转型为 人)
2、观察者(Observer)
Observer代表了观察者,在事件模型中它是事件的消费方,而在异步结构中,它一般是活动在主线程,可以想象成现实生活中的 人,它主要是一个接口,我们可以看代码
public interface Observer<T> {
void onCompleted();
void onError(Throwable var1);
void onNext(T var1);
}
其中包含了三个方法
1、onCompleted():
表示结束,当所有逻辑都执行完成,事件被完全消费以后调用。
2、onError():
表示错误,当处理逻辑时出现错误,会立即调用这个方法。
3、onNext():
表示消费事件:消费时间时回回调这个方法,与onError()方法互斥。
而提到ObServer就不得不提到它的一个衍生类Subscriber,它集成之Observer,所以包含了上面的三个方法,同时内部主要还扩展了两个方法。
public abstract class Subscriber<T> implements Observer<T>, Subscription {
private final SubscriptionList subscriptions;
protected Subscriber() {
this.subscriptions = shareSubscriptions && subscriber
!= null?subscriber.subscriptions:new SubscriptionList();
}
public final void add(Subscription s) {
this.subscriptions.add(s);
}
public final void unsubscribe() {
this.subscriptions.unsubscribe();
}
public final boolean isUnsubscribed() {
return this.subscriptions.isUnsubscribed();
}
//省略
..............
}
可以看到,它内部存在了一个SubscriptionList类,里面封装了一个LinkedList集合,当我们实现多订阅(包括单订阅)时就可以依据
1、unsubscribe():
当前观察者是否订阅有被观察者
2、isUnsubscribed():
是否订阅
这两种状态了
3、被观察者(Observable)
Observable代表了被观察者,在事件模型中它主要是事件的产生方,而在异步结构中,一般是活动在子线程,可以想象成现实生活中 天空
这是我剪切了一段Observer的代码,底部省略了很多关于操作符的代码,因为那是一段巨多的代码块,下面再讲,这里主要看一下Observable的创建。
//code RxJavaHooks.java
public class Observable<T> {
@ROOT {1}
final Observable.OnSubscribe<T> onSubscribe;
//这里主要是一个代理,利用了AOP的编程思想,做了一层拦截
@ROOT {2}
private static final RxJavaObservableExecutionHook hook
=
RxJavaPlugins.getInstance().getObservableExecutionHook();
@ROOT {3}
public static final <T> Observable<T> create(Observable.OnSubscribe<T> f) {
return new Observable(hook.onCreate(f));
}
protected Observable(Observable.OnSubscribe<T> f) {
this.onSubscribe = f;
}
//省略
............
}
首先, @ROOT {1}: 一个onSubscriber,它是一个Observable内部的全局接口变量,如果你有认真看过上面的小节,你理解起来必然会轻松很多,它就是一个起到了通知作用的接口,主要在订阅的一瞬间告知Observable可以传递数据了。
然后,@ROOT {2}:这里有一个Hook类,并且它是一个 静态 的被 final 修饰的类,如果熟悉AOP编程思想的同学估计会很好理解了,实际就是在构建Observabler的时候这里做了一层拦截,或者说是一次hook,也就是我们俗称的钩子,这里不同与我们经常挺高的JNI_HOOK,它是一个JAVA_HOOK,听起来很厉害,但其实内部主要就是一个代理类,而且是静态代理类,主要作用就是对onSubscriber的方法做一些代理,这里主要针对 call 方法的管理
最后,@ROOT {3}:在我们调用create()时,这里会将我们传递过来的onSubscriber实例进行一次代理封装,也就是用RxJavaObservableExecutionHook的onCreate给hook住,转化成一个内部被替换的OnSubscriber的对象。这里可能有人会有些疑惑,但是如果你点开hook.onCreate(f)的代码,会看到如此简洁的三行代码
public <T> OnSubscribe<T> onCreate(OnSubscribe<T> f) {
return f;
}
你会发现在里面它几乎什么都没有做,只是将传递进来的实例又返回出去了,看起来很无聊,但是这里需要注意的是,它已经获取到了onSubscriber的实例了,熟悉AOP切面编程的人估计会容易理解很多,因为这里相当与是对onSubscriber进行了一次代理,这样做的好处就是在合适的时机更加灵活并且适当的针对onSubscriber的生命周期进行管理,比如下面的源代码调用。
//Observable code
private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable) {
............ //省略
try {
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn((Subscription)subscriber);
} catch (Throwable var7) {
return Subscriptions.unsubscribed();
}
............ //省略
}
//RxJavaObservableExecutionHook code
public <T> OnSubscribe<T> onSubscribeStart(Observable<? extends T> observableInstance, OnSubscribe<T> onSubscribe) {
return onSubscribe;
}
第一段就是subscribe()方式的剪切,而第二个就是 Hook 中的内部实现,这里我们需要分成两个步骤来分析。
一、调用hook的onSubscribeStart()方法,传入Observable和OnSubscribe,内部也没有做任何处理,直接返回OnSubscribe(订阅行为)对象。这个OnSubscribe(订阅行为)对象就是Observable所持有的OnSubscribe,即我们在以前创建的那个OnSubscribe
二、调用OnSubscribe的call()方法,此时将之前创建的Subscriber作为参数传进去。这里就会触发先前我们在OnSubscribe的call()方法中编写好的各种操作和Subscriber的事件操作(如onNext,onCompleted等),相当于提供了一个内嵌的设计模式。
以上两步执行完毕,Observabler差不多也就能实现基本功能了,简单来说就是在订阅的瞬间对onObsubscriber的call方法的调用。然后就是关于变换的巨量代码了,稍后再详细分析。
4、订阅关系(subscribe)
正常逻辑应该是Observer.subscriber(Observabler),这样可以产生订阅关系,但是在Rxjava中,由于为了实现链式调用的形式变现,则更改为Observabler.subscriber(Observer),这看起来是一个很小的改动,但我在建模思考的时候,则感觉给自己照成了很大的困扰,因为我更倾向于将它按照正常逻辑思维来分析,因人而已吧,根据代码分析就是将Observer的实例通过onSubscriber传递给Observabler,这样就可以利用Observer实例调用方法传递数据了。
用自然语言总结起来就是
人 (Observer) 观测 (subscribe) 天空 (Observable)
通过风向标 (OnSubscriber)来传递消息,因为它在人的目光(Observer实例)中
如果天空 (Observable) 产生了风(Task) ,它会吹动风向标(onSubscriber),最后在风向标上的目光(Observer的实例)会告诉 人(Observer)起风了
很简单的一个事件模型,值得一提的就是跟其他帖子上说的观察者模型比较,唯一不同的就是我在其中加入了一个 风向标 和 目光 的概念,如果读上面的这段话你还是会产生迷惑的话,不用心急,看下面一段Rxjava简单调用方式,我估计你会立刻清晰起来,毕竟我就是在这段代码的基础上强行 建模 而成的。这里大家先不用纠结它内部的具体逻辑实现,只需要知道它的表现形式就好。
2、仿造一个简单的“Rxjava”
好了,到目前为止我们应该已经知道了Rxjava中用的到的的设计模式了,但是仍然没有提到过任何有意义的逻辑实现,这点也希望大家不要急,淡定一些,从容一些,我们这时候可以尝试的着去喝点水,或者是上个厕所之类的,因为我下面还是不会带着大家看Rxjava的具体逻辑实现,哈哈,有没有一种贱贱的赶脚!
开个玩笑啊,首先这里我要强调一下,Rxjava其实是一个很牛逼的第三方库,其中包括它的框架设计,包括它的代码逻辑,同样也包括它的扩展性,稳定性等等,但是归根结底,它的重中之中,仍然是利用了一个观察者模式来实现了事件的传递,变换。
这一小节我其实是打算直接看源码的,但是我发现逐步分析源码其实是一个拆轮子的过程,相对于一些基础比较薄弱的人可能会觉得不知所措,看的欲仙欲死的。
但是如果我们换一种思路,比如刚刚我贴了一张Rxjava的简单使用的代码图,那我们想想,如果在不看它源码的情况下能否实现这样的一个调用形式呢,答案一定是肯定。所以,有的时候既然用拆轮子的方式行不通,那我们就自己造一个轮子,当然,只是形似而已,但这样也能让我们更深刻的理解框架内部的实现形式,有助于我们在接下来比较轻松的分析源码了。
这里给大家推荐一篇博客,我认为写的相当可以了,链接如下:
带你造轮子系列:Rxjava
OK,这里我们就废话不多说,直接上代码了,毕竟只是实现了一个类似Rxjava简单调用的代码逻辑,让大家更加深刻理解上一小节讲过的东西,而且我比较习惯加注释,希望大家能一目了然。
首先是 Observabler 观察者
//观察者
public class Observable {
//存在于被观察者中的一个接口,主要用于通知被观察者被订阅
private OnSubscriber mOnSubscriber;
//定义通讯接口
interface OnSubscriber {
void call(Observer observer);
}
//私有化构造方法
private Observable(OnSubscriber onSubscriber) {
mOnSubscriber = onSubscriber;
}
//利用简单工厂类创建一个观察者
public static Observable create(OnSubscriber onSubscriber) {
return new Observable(onSubscriber);
}
//订阅
public void subscriber(Observer observer) {
//订阅后,利用OnSubscriber接口通知被观察者订阅关系成立,可以产生数据了
//同时将观察者的实例传递过去,用于数据的传输
this.mOnSubscriber.call(observer);
}
}
接着是 Observer 观察者
//观察者
public interface Observer<T> {
void onNext(T data);
}
没有看错,它就是一个简单的接口,内部存在一个方法,可以想象成 看 的动作
最后就是调用了,几乎跟Rxjava一模一样的形式
Observable.create(new Observable.OnSubscriber() {
@Override
public void call(Observable.Observer observer) {
observer.onNext("storm");
}
}).subscriber(new Observable.Observer() {
@Override
public void onNext(Object o) {
LogUtils.e("看到 = " + o);
}
});
粘完收工!简单的Rxjava就实现了,当然这有也许有小伙伴不愿意了。
:“这不就是一个简单的观察者模式吗。”
:“没错,它就是,同样Rxjava也是。”
最后,你们懂得,这虽然实现了一个很简单的“Rxjava”,但它至少已经可以表示出Rxjava的基本体系结构和核心功能类了。
3、变换
开头有讲到,在RxJava中功能的核心其实有两个,除了异步外还有一个更加厉害的地方就是 变换 了,它也正是RxJava操作符的核心,同样也是大多数人说『RxJava 真是太好用了』的最大原因。
而变换的定义是什么呢,这里借用仍物线的一句话:
变换:就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列
抽象来说也就是在刚刚的响应式编程模型中,我们对鱼做的一系列操作,下面先说说我认为RxJava中比较实用的几个操作符。
1、map()`
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(1);
}
}).map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
String transformation = integer + "拼接成一个String类型";
return transformation;
}
}).subscribe(new Action1<String>() {
@Override
public void call(String o) {
LogUtils.e(o);
}
});
在map操作符中,需要传入一个Func1,它是一个继承自Function的接口,在变换逻辑中,Function其实算是一个比较核心的接口了,我们直接看看Function的实现
public interface Func1<T, R> extends Function {
R call(T var1);
}
很清晰的一个代码块,它用泛型规范了一种变换逻辑,传入的是 T,返回的就是 R了。