在之前的几篇博客中,我编写了一篇有关Rxjava学习笔记的,还有一个是RxJava使用示例(一): 实现Rxbus代替eventbus(这篇博文其实还不算完善,因为没有对被观察者发出的时间进行一个筛选,一次发送所有订阅者都会收到,这样不太好,可以再新加一个筛选器,等以后有空或者是遇到的时候再来改一改,现在不急)。
之前在写那边Rxjava学习笔记的时候,就突出了一点是只涉及使用,不涉及原理,现在就对Rxjava的原理进行一个简单的探索。
Rxjava属于一种扩展性的观察者模式,里面的四个基本概念是:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
另外有一点是需要注意的,也是Rxjava很重要的一个特性,里面的onError方法,只要是发生错误的话就一定会被处理,所以可以将一些错误处理的代码直接写在onError中。
还有一点就是,Rxjava跟普通的观察者模式的区别在于如果observable没有任何Observer的话是不会发出任何事件的。
Observable负责在发生什么事件或者是订阅的对应条件产生时,就会发送事件去通知Observer,而具体的如何操作是有Observer接收到之后自己处理的,也就是说Observable只负责发,其余的处理由Observer自己来处理。
在Rxjava中存在flatMap以及Map,他们可以将一些指定的要发送的对象类型转换为另一个需要的对象类型,而这一个在Rxjava中是如何实现的呢?下面是我自己的一些理解,可能会有错误或偏差,欢迎指点。
// 这是摘自扔物线的精简后的lift代码
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);
}
});
}
代码中存在一个lift()方法,这个方法就是flatMap以及Map能够转换对象类型的关键。这里就只总结一下思路:
通过这个lift方法会创建一个新的observable,这个observable里面包含一个新的OnSubscribe,一个新的subscriber。
当用户调用经过 lift() 后的 Observable 的 subscribe() 的时候,使用的是新的 Observable
于是它所触发的 onSubscribe.call(subscriber),也是用的新 Observable 中的新
OnSubscribe。 而这个新 OnSubscribe 的 call() 方法中的 onSubscribe ,就是指的原始
Observable 中的原始 OnSubscribe ,在这个 call() 方法里,新 OnSubscribe 利用
operator.call(subscriber) 生成了一个新的 Subscriber(Operator 就是在这里,通过自己的
call() 方法将新 Subscriber 和原始 Subscriber 进行关联,并插入自己的『变换』代码以实现变换),然后利用这个新
Subscriber 向原始 Observable 进行订阅。
也就是说,原始的onSubscribe方法会发送数据发送到这个新的Subscriber中,而在这个新的Subscriber中会对数据进行一个处理,处理完成之后再发送给目标订阅者,也就是最原始的observer。而至于为什么要先发送数据到一个新的subscriber中,上面也提到过了,observable只管发,数据的处理是在subscriber中处理,这样分工明确。而当新的这个观察者处理完数据之后,再转发给原始的观察者。
最开始我接触到Rxjava有三个原因:
第一个是代码的简洁度,链式。
第二个是响应式框架,观察者模式。
第三个就是它是一个异步的框架,线程切换功能极其强大,可任意指定观察者发生的线程以及被观察者的线程,随意调整极其强大(观察者发生的线程只能更改一次,被观察的可以随意切换)。
而之前也是一直都很好奇它的这个切换的流程是怎么样的,为什么只能观察者发生的线程只能更改一次而被观察的可以随意切换多次?
线程的切换其实也是使用了上面介绍到的lift方法,被观察者切换线程使用observeOn(),观察者切换线程使用subscriberOn(),可切换为多种线程,例如主线程,IO线程,新线程等等,具体的可以查看我的第一篇Rxjava博文,Rxjava学习笔记。
observeOn()
在lift方法后,会创建一个新onSubscribe和一个新的subscriber。新的onSubscribe会通知原始的onSubscribe,原始的在收到通知后就会把信息发送到新的subscriber中,而这个时候如果设置了切换线程的话就会发生切换线程的操作
subscribeOn()
而subscribeOn()方法就不同了,它切换线程的位置是在新onSubscribe通知原始onSubscribe之前,这也就导致了如果设置了多个切换线程操作始终只有有第一个subscribeOn()方法切换成功,因为它切换线程是在整个的流程发生之前,而当第二个subscribeOn()方法调用时它已经是处于整个流程之中了,因此就无法设置多个。而observeOn()则不同,它的线程切换是发生在流程之中的,所以多个切换是被允许的。
总结到了这里,我产生了一个疑问,subscribeOn切换观察者的线程为什么要设置在整个流程之前而为什么observeOn方法会设置到整个流程之间?这个应该是创造者指定的一个规则吧,但是我很好奇为什么要这样设置。
————————————————— 更新
通过在stackOverFlow以及知乎上提问获得了想要的答案:
我的理解是subscribeOn是影响生产者(Observable)生产数据的线程的,通常我们只需要指定生产者在某一个特定的线程生产数据就可以满足我们的需求,至少我还没遇到过需要在生产数据的过程中去切换生产者所在的线程的情况。绝大多数我们需要变化线程的场景都是在数据生产之后,Rx里面就使用observeOn来指定各种operator和subcriber的线程,因为这些本质上都是数据的消费者。消费者可以任意切换自己接受处理数据的线程,足以满足我们的需求。
作者:hi大头鬼hi