关于RxJava源码的分析

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值