RxJava最近好像真的比较火,我也算是接触了一段时间了,它的确对于提升代码的简洁性,避免多嵌套这一块有很大的帮助。我对RxJava的宏观理解是观察订阅模式+一系列的诸如compose、map、flapMap等操作符运用的集合,而观察者模式氛围两个部分,一是被观察者Observable,另一个就是订阅者Subscriber,观察者持有订阅者的引用,能够在执行一系列操作后,通过该引用执行订阅者方法,从而达到观察者中的事件传递到订阅者的目的。
Observable中的操作可以是一个数据库查询,Subscriber用来显示查询结果;Observable可以是屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求,Subscriber用来显示请求结果。另外Observable和Subscriber中间可以添加任意多的操作符,操作符中对前面的Observable数据进行处理,并返回Observable最终将数据交给Subscriber。
本文的目的是通过分析源码,了解RxJava观察订阅实现原理,并通过map操作符为例说明操作符使用原理。
1、观察订阅模式实现
先看看常规使用RxJava实现观察订阅模式的代码吧,观察订阅里的观察实际上市被观察的意思。
被观察者:
Observable<String> myObservable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("hello world");
subscriber.onCompleted();
}
});
被观察者Observable代码很简单,这里要注意的是create方法的参数类型是一个OnSubscribe,这个OnSubscribe实际上是一个连接器,其实现方法call中的Subscribe类型参数,实际上就是对订阅者Subscribe对象的一个引用,然后在call方法中完成一系列操作用,就可以调用订阅者的方法来提醒订阅者该干活了。
订阅者:
Subscriber<String> mySubscriber = new Subscriber<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
System.out.println(s);
}
};
订阅者实现onCompleted、onError、onNext几个方法(实际上还有一个onStart方法,该方法能够再Observable调用call之前进行一些非UI操作),上面OnSubscribe方法call中执行subscribe.onNext以及subscribe.onCompleted方法时,便会执行到这里的订阅者的具体方法中来。
订阅操作:
myObservable.subscribe(mySubscriber);
订阅操作是核心,通过订阅将被观察者和订阅者二者联系起来(实际起到连接作用的是OnSubscribe类),并且subscribe方法最终会执行OnSubscribe对象的call方法,也就是说这里的订阅操作在订阅的同时启动了观察者的逻辑代码(也就是call方法)。
以上代码看起来RxJava观察订阅模式,貌似由三部分组成,实际上我们这里总结出四个组成部分
a、被观察者 Observable
b、连接器 OnSubscribe(也是实际触发订阅者方法的地方)
c、订阅者 Subscriber
d、订阅操作
2、观察订阅实现源码分析
以上的一个针对RxJava实现观察订阅者模式的总结可会让能多童鞋产生一堆的疑惑,没关系,我们这一小节从源码的角度来说,希望能够多少解决一些疑惑。
这里从订阅操作subcribe这个方法入手吧,该方法会调用到Observable.subscribe方法,该方法的参数一个是订阅者,一个是被观察者。
private static <T> Subscription subscribe(Subscriber<? super T> subscriber, Observable<T> observable)
Observable.subscribe方法中又以下代码
// new Subscriber so onStart it
subscriber.onStart();
/*
* See https://github.com/ReactiveX/RxJava/issues/216 for discussion on "Guideline 6.4: Protect calls
* to user code from within an Observer"
*/
// if not already wrapped
if (!(subscriber instanceof SafeSubscriber)) {
// assign to `observer` so we return the protected version
subscriber = new SafeSubscriber<T>(subscriber);
}
// The code below is exactly the same an unsafeSubscribe but not used because it would
// add a significant depth to already huge call stacks.
try {
// allow the hook to intercept and/or decorate
hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);
}
这里的hook.onSubscribeStart方法返回的是observable.onSubscribe,其实也就是Observable.create中的OnSubscribe连接器对象,然后调用该连接器的call方法,call方法传入的参数就是订阅器Subscriber对象,于是乎从OnSubscribe的call方法就执行到了订阅器Subscriber的onNext等方法了。
这里的hook是一个RxJavaObservableExecutionHook对象,其onSubscribeStart方法为
public <T> OnSubscribe<T> onSubscribeStart(Observable<? extends T> observableInstance, final OnSubscribe<T> onSubscribe) {
// pass-thru by default
return onSubscribe;
}
所以我们能够理解了上面说的hook.onSubscribeStart方法返回的是observable.onSubscribe。
另外在hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);这个代码之前还调用了一下代码
subscriber.onStart();
这就说明在执行call方法之前订阅器Subscriber可以通过重载onStart方法干一些事情。
3、map操作符使用
如果RxJava仅仅就实现了一个观察订阅模式,那么现在看起来,它没有使代码变简单,反而使代码变得更加复杂了,而RxJava的真正魅力在于各种操作符的使用,操作符使得被订阅者Observable中的call返回参数,可以在操作符中进行进一步的处理,然后返回Observable最后才订阅到订阅器Subscriber。这里说说map操作符的使用吧。
接着第一小节实现的代码,被观察者、订阅者代码不变、只是修改下订阅操作(由此可以看出需求改变时,操作符的使用可以使得代码改动很小)。
修改后的订阅操作代码为:
myObservable.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s + "-yoryky";
}
}).subscribe(mySubscriber);
这里map方法接收的参数是
public interface Func1<T, R> extends Function {
R call(T t);
}
这个Func1接口的实现类需要实现Func1.call方法,Func1.call方法的参数便是OnSubscribe.call方法的返回参数,于是在Func1.call方法中便可以对其进行进一步的处理,由map方法返回Observable再订阅到定于器Subscriber,这话可能说的有点糊涂,还是通过下一下节的map对应源码来看吧。
4、map操作符对应源码分析
map操作符首先调用到Observable.map方法
public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
return lift(new OperatorMap<T, R>(func));
}
从这里可以看到map操作符返回Observable参数,再看这个lift方法传的参数是OperatorMap类型的
return lift(new OperatorMap<T, R>(func));
跟到lift方法中去
public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {
return new Observable<R>(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> o) {
try {
Subscriber<? super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
onSubscribe.call(st);
} catch (Throwable e) {
// localized capture of errors rather than it skipping all operators
// and ending up in the try/catch of the subscribe method which then
// prevents onErrorResumeNext and other similar approaches to error handling
Exceptions.throwIfFatal(e);
st.onError(e);
}
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
// if the lift function failed all we can do is pass the error to the final Subscriber
// as we don't have the operator available to us
o.onError(e);
}
}
});
}
我们发现lift方法中又新建了一个Observable对象并返回,对应的Observable对象有一个连接器OnSubscribe(被观察者好像比较主动,自带连接器,还带有对订阅者的引用,对订阅者了若指掌),重点在这个OnSubscribe.call方法中,有下面的代码
Subscriber<? super T> st = hook.onLift(operator).call(o);
这里又有这个hoot.onLift方法,该方法返回operator也就是OperatorMap对象,而OperatorMap.call方法为
@Override
public Subscriber<? super T> call(final Subscriber<? super R> o) {
return new Subscriber<T>(o) {
@Override
public void onCompleted() {
o.onCompleted();
}
@Override
public void onError(Throwable e) {
o.onError(e);
}
@Override
public void onNext(T t) {
try {
o.onNext(transformer.call(t));
} catch (Throwable e) {
Exceptions.throwOrReport(e, this, t);
}
}
};
}
好家伙,OperatorMap.call居然又返回一个订阅器,并且在订阅器的onNext方法中调用了
o.onNext(transformer.call(t));
这个transformer是啥呢,就是map方法参数Func1的引用。
而Observable.lift方法中
Subscriber<? super T> st = hook.onLift(operator).call(o);
try {
// new Subscriber created and being subscribed with so 'onStart' it
st.onStart();
onSubscribe.call(st);
}
st为OperatorMap.call方法返回的订阅器,onSubscribe为myObservable中的OnSubscribe引用,而
onSubscribe.call(st);
这个方法实际上就是myObservable对象,调用了一个由map操作符创建的新的订阅器,所以myObservable中OnSubscribe.call方法执行subscriber.onNext等操作时,会执行到map操作符创建的新的订阅器上,而不是最后由subscribe方法订阅的那个订阅器上。另外map方法还返回新的Observable对象,所以map操作符的作用可以用下图表示
看了map操作符相关源码,我的感觉是,我去,天才啊,这都谁想到的。。。。
到这里本文的主要任务就结束了,可能讲的不怎么详细,都只说了个大概。因为关于RxJava观察订阅模式的源码解读已经有童鞋写的很好很详细了,所以本文就抓骨架来说的,如果有需要可以看参考文献。
另外本人RxJava初学,如有不对的地方,还请指出啊。
5、参考文献
1、Rxjava 源码分析(一):http://www.jianshu.com/p/814b63036c78
2、深入浅出RxJava(一:基础篇):http://blog.csdn.net/lzyzsd/article/details/41833541