一.手写create操作符
1.UML类图与执行流程
上面就是我们类图及类关系,我们来看一段调用代码:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservablseEmitter<Integer> e) throws Exception {
e.onNext(1);
}
}).subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
//虽然是null,但是有用
System.out.println("onSubscribe:" + d.hashCode() + "---------------->>>>>" + d);
}
@Override
public void onNext(Integer s) {
System.out.println("onNext:" + s);
}
@Override
public void onError(Throwable e) {
System.out.println("onError:" + e.getMessage());
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
});
}
我们可以看到,当我们调用create方法时,返回的是一个observable对象,并且我们传入了一个事件绑定源接口ObservableOnSubscribe,当我们订阅时,即调用subscribe时需要传入一个Observe接口。
当我们执行订阅subcribe时,会执行ObservableCreate中ObservableOnSubscribe中的subscribe方法,它是个接口,所以我们传入的实现类中的subscribe方法会被调用,从而调用事件接口发送事件,当发送时(执行e.next(1)),它又是个接口,真正实现的是在(subscribe)订阅时ObservableCreate中有个ObservablseEmitter实现类,它是我们订阅时会传入的observe,于是这里的他在实现中又直接调用了observer接口象的方法,所以我们传入的Observe的现就会收到。所以Rx虽然本质上是一个观察者模式,但是它其实接口化了绑定关系和事件源,并且使用链式调度,让我们不在陷入回调地狱。
2.手写create操作符
那么我们就按照这个逻辑自己写一个create操作符,并且按照它的逻辑实现:
1.事件源绑定接口
public interface MyObservableOnSubscribe<T> {
/**
* 这个给用户 通过接口发送事件
* @param e
*/
void onSubscribe(MyObservableEmitter< T> e);
}
2.事件接口(实现类存在在框架中,create调用时会调用到observe方法)
public interface MyObservableEmitter <T>{
void onNext(T t);
void onError(Throwable throwable);
void onComplete();
}
3.被观察者
public abstract class MyObservable<T> {
private MyObservableOnSubscribe<T> source;
public void subscribe(MyObserve< T> observe){
this.subscribeActual(observe);
}
abstract void subscribeActual(MyObserve<? super T> observe);
public static <T> MyObservable<T> create(MyObservableOnSubscribe<T> source){
return new MyObservableCreate<T>(source);
}
}
4.观察者
public interface MyObserve<T> {
void onNext(T t);
void onError(Throwable throwable);
void onComplete();
void onSubscribe();
}
5.create操作符
public final class MyObservableCreate<T> extends MyObservable<T> {
/**
* 事件源
*/
final MyObservableOnSubscribe<T> source;
/**
* 事件源接口,事件由外部传入
*
* @param source
*/
public MyObservableCreate(MyObservableOnSubscribe<T> source) {
this.source = source;
}
/**
* 真正的绑定
*/
@Override
protected void subscribeActual(MyObserve<? super T> observe) {
MyEmitter<T> emitter = new MyEmitter<T>(observe);
observe.onSubscribe();//这里才开始真正的绑定
source.onSubscribe(emitter);
//事件源和emitter绑定了
// 用户通过emitter接口其实相当于observe的代理
}
class MyEmitter<T> implements MyObservableEmitter<T> {
//通知观察者实现
private final MyObserve<? super T> observe;
public MyEmitter(MyObserve<? super T> observe) {
this.observe = observe;
}
@Override
public void onNext(T t) {
observe.onNext(t);
}
@Override
public void onError(Throwable throwable) {
observe.onError(throwable);
}
@Override
public void onComplete() {
observe.onComplete();
}
}
}
6.调用测试
public void testMyRx(){
MyObservable.create(new MyObservableOnSubscribe<Integer>() {
@Override
public void onSubscribe(MyObservableEmitter<Integer> e) {
e.onNext(1);
}
}).subscribe(new MyObserve<Integer>() {
@Override
public void onNext(Integer integer) {
System.out.println("testMyRx integer :"+integer);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe() {
System.out.println("testMyRx onSubscribe--->");
}
});
二.手写map操作符
这次我们先看代码在说原理,代码如下:
1.手写实现
1.装饰器
public abstract class MyAbstractUpStreamObservable<X,Y> extends MyObservable<Y> {
final MyObservable<X> upStream;
protected MyAbstractUpStreamObservable(MyObservable<X> upStream) {
this.upStream = upStream;
}
}
2.map操作符
public class MyObservableMap<X, Y> extends MyAbstractUpStreamObservable<X,Y> {
final MyFunction<X, Y> function;
public MyObservableMap(MyObservable<X> upStream, MyFunction<X, Y> function) {
super(upStream);
this.function = function;
}
@Override
protected void subscribeActual(MyObserve<? super Y> observe) {
MyMapperObserve<X,Y> tMyMapperObserve = new MyMapperObserve<>(observe, function);
upStream.subscribe(tMyMapperObserve); //注册上游被观察者的观察者
}
//上游的观察者 这里做下转换就可以转成下游的观察者了
class MyMapperObserve<X,Y> implements MyObserve<X> {
final MyObserve<? super Y> downStream;//下游的观察者
final MyFunction<X,Y> mapper;
public MyMapperObserve(MyObserve<? super Y> observe, MyFunction<X, Y> mapper) {
this.downStream = observe;
this.mapper=mapper;
}
@Override
public void onNext(X t) {
Y u = mapper.apply(t);
downStream.onNext(u); //下游的观察者响应
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe() {
downStream.onSubscribe();
}
}
}
3.Function接口
public interface MyFunction<T,R>{
R apply(T t);
}
4.创建端
public <T,U>MyObservable<U> mapper(MyFunction<T,U> mapper){
return new MyObservableMap( this,mapper);
}
5.调用测试
public void testMyRxMapper(){
MyObservable.create(new MyObservableOnSubscribe<Integer>() {
@Override
public void onSubscribe(MyObservableEmitter<Integer> e) {
e.onNext(1);
}
}).mapper(new MyFunction<Integer, String>() {
@Override
public String apply(Integer integer) {
return integer+"---";
}
})
.subscribe(new MyObserve<String>() {
@Override
public void onNext(String integer) {
System.out.println("testMyRxMapper integer :"+integer);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe() {
System.out.println("testMyRxMapper onSubscribe--->");
}
});
}
2.代码解析
我们分析下mapper的代码,首先我们为什么使用装饰器模式去设计mapper,我们要了解mapper的功能,它是给原来的被观察者做转换的,但是转换的对象是被观察者,如果我们继续使用继承的方式,后面如果有更多的转换功能是不是就会有更多的派生类,并且派生类中有些功能是重复的,拿生活的例子来说,比如我们的饭是基类,蛋炒饭和牛肉饭都是派生出来的,我们要吃牛肉蛋炒饭,是做子类好还是使用装饰器好?显然装饰器的可能会更好,因为装饰器可以装饰任意一层子类,它只需要基类的引用,如果你想要为子类添加任何功能,你只传入任何子类和对应的装饰功能即可,所以我们使用装饰器模式,并且在java中IO流就是使用装饰器添加了各种功能。
我们在分析下执行过程,我们先来分析下上游的流过程,也就是我们在创建被观察者的过程,那他其实就是一个套娃过程,比如我们创建mapper的时候,传入的是上一个观察者,那下游订阅的过程才是真正执行的过程,mapper的内部会创建一个观察者,观察上游的事件,然后在通过传入进来的function方法,进行数据转换,当然这个具体的转换方法,是由外部用户传入,转换完成后,又调用真正的外部观察者调用。
三.手写线程切换
1.线程调度器
在Rxjava中的线程调度这块,主要给我们提供了三个大类,一个是线程调度的Schedule它负责提供一个线程调度执行的最小单元Worker的模板方法,在Worker中会提供具体的执行方法,也就是schedule方法,需要我们从外部传入一个runnable,这样我们就可以在worker最小执行单元中将runable放到不同的线程中执行,并且给我们提供了Schedules这个类中的几个常用的静态的调度器变量。所以我们按照它的逻辑写个自己的线程调度器。
public abstract class MySchedule {
/**
* 线程调度器
* 提供模板可以创建不同的工作执行具体的线程操作
* Schedule : Worker = 1:N
*
* @return
*/
public abstract MyWorker createWorker();
/**
* 最小执行单元,提供模板方法,让不同的线程执行run方法,从而达到线程切换的目的
*
*/
public static abstract class MyWorker{
public abstract void schedule(Runnable runnable);
}
}
public class MyCacheThreadSchedule extends MySchedule{
ExecutorService executorService= Executors.newCachedThreadPool();//多个worker对应一个线程池
@Override
public MyWorker createWorker() {
return new MyWorker() {
@Override
public void schedule(Runnable runnable) {
executorService.execute(runnable);
}
};
}
}
public class MySchedules {
private MySchedules(){}
public static MySchedule new_thread=null;
private static MySchedules instance;
static {
instance=new MySchedules();
new_thread=new MyCacheThreadSchedule();
}
}
2.切换上游
我们参考mapper操作符,写一个对上游切换的操作符,核心原理就是在subscribeActulal中,将上游的subscribe方法放到worker的task中去。
public class MyObservableSubscribeOn<X> extends MyAbstractUpStreamObservable<X,X> {
final MySchedule schedule; //外部传入的执行器
public MyObservableSubscribeOn(MyObservable<X> upStream,MySchedule schedule) {
super(upStream);
this.schedule=schedule;
}
@Override
protected void subscribeActual(MyObserve<? super X> observe) {
MySubscribeOnObserve<X> upObserve=new MySubscribeOnObserve<>(observe); //上游的观察者
SubscribeTask subscribeTask = new SubscribeTask(upObserve);
MySchedule.MyWorker worker = schedule.createWorker();
//上游的订阅操作放到指定的runnable中去
worker.schedule(subscribeTask);
}
//上游的观察者
final static class MySubscribeOnObserve<X> implements MyObserve<X>{
final MyObserve<? super X > downStream;//下游的观察者
MySubscribeOnObserve(MyObserve<? super X> downStream) {
this.downStream = downStream;
}
@Override
public void onNext(X x) {
downStream.onNext(x);
}
@Override
public void onError(Throwable throwable) {
downStream.onError(throwable);
}
@Override
public void onComplete() {
downStream.onComplete();
}
@Override
public void onSubscribe() {
}
}
final class SubscribeTask implements Runnable{
final MySubscribeOnObserve<X> parent;
SubscribeTask(MySubscribeOnObserve<X> parent) {
this.parent = parent;
}
@Override
public void run() {
upStream.subscribe(parent); //上游的订阅 将上游的订阅放到指定的线程执行
}
}
}
我们写个测试看下:
public void testMyRxMapperSubscribeOn(){
MyObservable.create(new MyObservableOnSubscribe<Integer>() {
@Override
public void onSubscribe(MyObservableEmitter<Integer> e) {
e.onNext(1);
System.out.println("testMyRxMapper current Thread name: "+Thread.currentThread().getName());
}
})
.mapper(new MyFunction<Integer, String>() {
@Override
public String apply(Integer integer) {
return integer+"---";
}
})
.subscribeOn(MySchedules.cacheThread)
.subscribe(new MyObserve<String>() {
@Override
public void onNext(String integer) {
System.out.println("testMyRxMapper onNext current Thread name: "+Thread.currentThread().getName());
System.out.println("testMyRxMapper integer :"+integer);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe() {
System.out.println("testMyRxMapper onSubscribe--->");
}
});
}
打印如下:
testMyRxMapperSubscribeOn current Thread name: pool-1-thread-1
testMyRxMapperSubscribeOn onNext current Thread name: pool-1-thread-1
testMyRxMapperSubscribeOn integer :1---
我们来捋一捋上面订阅的执行流程:
1.捋清楚套娃的关系,我们的线程切换的被观察者持有的是mapper这个被观察者的引用,而mapper被观察者中又持有create操作符创建的被观察者。
2.捋清楚订阅关系,SubscribeOn是由外部订阅,内部订阅Mapper,Mapper是由SubscribeOn订阅,内部订阅Create,Create的被Mapper订阅,内部订阅事件发射器。
当我们在SubscribeOn中的订阅时,它会执行Mapper中的订阅,而mapper中的订阅又会执行create中的订阅方法,所以subscribeOn的订阅会让上游所有的订阅都执行到指定的schedule中去。
3.捋清楚执行关系,我们上面已经分析了套娃的过程以及订阅过程,我们再来看看执行过程,当create中的emitter发射事件时,(这个也会在前面指定的线程执行,因为我们的create的订阅中监听了emitter事件的执行),create中的观察者会被执行,因为create是被mapper观察者的,create持有Mapper种的观察者引用,所以mapper的观察者会被执行,又因为mapper是被subscribeon观察的,Mapper中持有subScribeOn的观察者的引用,那subscribeon是被外部观察者观察的,那么外部的观察者就得到了执行。
可以看到,我们上游的线程切换后,下游的执行也会被切换到特定的线程调度中去,所以我们对下游也需要线程切换。
3.切换下游
通过前面的知识,我们已经掌握到了,如果想切换下游,其实就是在执行上游的观察者的方法时在将调用下游的观察者的方法放到执行的线程中去,那这个就很好办了,我们写一个MyObserveOn观察者,观察上游链条的观察者,并且接收下游的观察者,当收到上游观察者发出的事件时,我们通过线程调度,将下游的执行放到该线程中执行,并且通过队列的形式将事件缓存到队列中执行。
public class MyObserveOn<X> extends MyAbstractUpStreamObservable<X, X> {
final MySchedule schedule; //外部传入的执行器
public MyObserveOn(MyObservable<X> upStream, MySchedule schedule) {
super(upStream);
this.schedule = schedule;
}
@Override
protected void subscribeActual(MyObserve<? super X> observe) {
MyObserveOnObserve<X> upObserve = new MyObserveOnObserve<>(schedule.createWorker(), observe); //上游的观察者
upStream.subscribe(upObserve);//执行订阅
// MySchedule.MyWorker worker = schedule.createWorker();
// worker.schedule(upObserve);
}
//上游的观察者
final static class MyObserveOnObserve<X> implements MyObserve<X>, Runnable {
final MySchedule.MyWorker worker;
final MyObserve<? super X> downStream;//下游的观察者
final Deque<X> deque;
volatile boolean over; //next中是否已经完全执行。
volatile boolean done;//是否已完成 如:抛异常
volatile Throwable error;//
MyObserveOnObserve(MySchedule.MyWorker worker, MyObserve<? super X> downStream) {
this.worker = worker;
this.downStream = downStream;
deque = new ArrayDeque<>();//双向队列
}
@Override
public void onNext(X x) {
//downStream.onNext(x);
//deque.add(x);//会抛异常
deque.offer(x);//将事件放到队列
schedule();//执行
}
@Override
public void onError(Throwable throwable) {
done = true;
error=throwable;
//downStream.onError(throwable);
}
/**
* 执行
*/
private void schedule() {
worker.schedule(this);
}
@Override
public void onComplete() {
done = true;
//downStream.onComplete();
}
@Override
public void onSubscribe() {
}
@Override
public void run() {
drainNormal();
}
//从队列中排放事件并处理
private void drainNormal() {
final Deque<X> xDeque = deque;
final MyObserve<? super X> inDownStream = downStream;
while (true) {
boolean d = done;
X x = xDeque.poll();//取出并删除 不会抛异常 x or null
boolean empty = x == null;
if (checkTerminal(d, empty, inDownStream)) {
//正常/异常退出、队列清空退出
return;
}
if(empty){
//再次判断是否为空 若为空 跳出循环
break;
}
downStream.onNext(x);
}
}
private boolean checkTerminal(boolean done, boolean empty, MyObserve<? super X> inDownStream) {
if (over) {
//如果执行完成了清空队列
deque.clear();
return true;
}
if (done) {
Throwable throwable = error;
if (throwable != null) {
//是否是异常退出
over = true;
inDownStream.onError(throwable);
return true;
} else if (empty) {
//正常退出
over = true;
inDownStream.onComplete();
return true;
}
}
return false;
}
}
}
下面我们做个简单的测试:
public void testMyRxMapperObserveOn(){
MyObservable.create(new MyObservableOnSubscribe<Integer>() {
@Override
public void onSubscribe(MyObservableEmitter<Integer> e) {
System.out.println("testMyRxMapperSubscribeOn current Thread name: "+Thread.currentThread().getName());
e.onNext(1);
}
})
.mapper(new MyFunction<Integer, String>() {
@Override
public String apply(Integer integer) {
return integer+"---";
}
})
.subscribeOn(MySchedules.cacheThread)
.observeOn(MySchedules.cacheThread)
.subscribe(new MyObserve<String>() {
@Override
public void onNext(String integer) {
System.out.println("testMyRxMapperSubscribeOn onNext current Thread name: "+Thread.currentThread().getName());
System.out.println("testMyRxMapperSubscribeOn integer :"+integer);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
@Override
public void onSubscribe() {
System.out.println("testMyRxMapper onSubscribe--->");
}
});
while (true);
}
我们看下打印:
testMyRxMapperSubscribeOn current Thread name: pool-1-thread-1
testMyRxMapperSubscribeOn onNext current Thread name: pool-1-thread-2
testMyRxMapperSubscribeOn integer :1---
可以看到通过observeon切换后,打印也变了。
四.总结
1.create操作符总结
我们通过手写create操作符知道了:1.事件的分发/获取,核心点是observableonScribe和emitter这两个接口,在Observable.create中我们需要传入这个接口的实现,所以事件是由外部传入的,并且是在Observable中通过emitter的实现来接收的。这个接收有点像观察者和被观察者:外部事件是被观察者,而内部emitter是观察者。2.事件的订阅,其实也是在subscribe中传入的外部观察者中,前面关于事件的分发我们应知道,Obsrevable中通过emitter的实现已经接收到外部的事件,所以拿到事件后我们会通过外部观察者将事件转发出去。以上就是事件的分发/获取,以及转发到外部观察者的过程。
2.map操作符
我们通过手写map操作符知道了:1.首先我们使用了装饰器模式,为什么以及什么是装饰器模式,这里就不说了,看前文;2.我们通过套娃的操作以及转换函数的方法,将观察到上游事件通过转换函数的方法转换后,在通过外部的观察者将事件转发出去。
3.线程切换
线程切换的手写其实也就比较简单了:1.上游的切换,其实就是在执行subscribe方法时传入调度器,然后就subscribe方法放到调度中的worker中的run方法中执行,通过不同的调度器就会切换到不同的线程,需要注意的是,因为上游subscribe会subscribe上游的事件,所以这个注册时传递的,也就是说这个线程切换对所有的上游都生效了,并且在顶层注册方法中,会监听事件的下发并转发事件,所以所有下游的事件执行也会被带到指定的线程中执行;2.下游的切换,这个也比较简单,只要在其内部将上游的事件放到队列中去,在循环调用下游的观察者执行即可。
4.流以及上下游的概念
在Rx中我们通过会用三个流来抽象概括它的流程,分别是:1.链式构建流,即:通过装饰器来套娃创建被观察者的过程;2.订阅流,即我们从外部订阅时会从下游一直往上游订阅也就是注册观察者的过程,当我们外部注册时,它会一直向上游注册,直到顶层为止;3.回调流,即事件的发射执行过程也就是观察者执行,我们知道事件是由顶层发射过来的,所以我们的回调也是从上游一直下发到下游。那上下游的概念也就很好理解,操作符前面的叫上游,下面的就叫下游。
5.线程切换的问题
1.我们在subscribeOn中切换,如果多次调用,最上游的subcribeon决定了上游的线程,因为订阅的流是自下往上的,所以上游切换的线程才会决定最终的事件发射的线程。
2.我们在observeon中的切换,只对下游生效。