一起来造一个RxJava,揭秘RxJava的实现原理

RxJava是一个神奇的框架,用法很简单,但内部实现有点复杂,代码逻辑有点绕。我读源码时,确实有点似懂非懂的感觉。网上关于RxJava源码分析的文章,源码贴了一大堆,代码逻辑绕来绕去的,让人看得云里雾里的。既然用拆轮子的方式来分析源码比较难啃,不如换种方式,以造轮子的方式,将源码中与性能、兼容性、扩展性有关的代码剔除,留下核心代码带大家揭秘RxJava的实现原理。

什么是响应式编程

首先,我们需要明确,RxJava是Reactive Programming在Java中的一种实现。什么是响应式编程? 
用一个字来概括就是流(Stream)。Stream 就是一个按时间排序的 Events 序列,它可以放射三种不同的 Events:(某种类型的)Value、Error 或者一个” Completed” Signal。通过分别为 Value、Error、”Completed”定义事件处理函数,我们将会异步地捕获这些 Events。基于观察者模式,事件流将从上往下,从订阅源传递到观察者。

至于使用Rx框架的优点,它可以避免回调嵌套,更优雅地切换线程实现异步处理数据。配合一些操作符,可以让处理事件流的代码更加简洁,逻辑更加清晰。

搭建大体的框架

要造一座房子,首先要把大体的框架搭好。在RxJava里面,有两个必不可少的角色:Subscriber(观察者) 和 Observable(订阅源)。

Subscriber(观察者)

Subsribler在RxJava里面是一个抽象类,它实现了Observer接口。

[java] view plain copy

  1. public interface Observer<T> {  
  2.     void onCompleted();  
  3.     void onError(Throwable t);  
  4.     void onNext(T var1);  
  5. }  

为了尽可能的简单,将Subscriber简化如下:

[java] view plain copy

  1. public abstract class Subscriber<T> implements Observer<T> {  
  2.     public void onStart() {  
  3.     }  
  4. }  


Observable(订阅源)

Observable(订阅源)在RxJava里面是一个大而杂的类,拥有很多工厂方法和各式各样的操作符。每个Observable里面有一个OnSubscribe对象,只有一个方法(void call(Subscriber<? super T> subscriber);),用来产生数据流,这是典型的命令模式。

[java] view plain copy

  1. public class Observable<T> {  
  2.     final OnSubscribe<T> onSubscribe;  
  3.   
  4.     private Observable(OnSubscribe<T> onSubscribe) {  
  5.         this.onSubscribe = onSubscribe;  
  6.     }  
  7.   
  8.     public static <T> Observable<T> create(OnSubscribe<T> onSubscribe) {  
  9.         return new Observable<T>(onSubscribe);  
  10.     }  
  11.   
  12.     public void subscribe(Subscriber<? super T> subscriber) {  
  13.         subscriber.onStart();  
  14.         onSubscribe.call(subscriber);  
  15.     }  
  16.   
  17.     public interface OnSubscribe<T> {  
  18.         void call(Subscriber<? super T> subscriber);  
  19.     }  
  20. }  

实践

到此,一个小型的RxJava的雏形就出来了。不信?我们来实践一下吧

[java] view plain copy

  1. Observable.create(new Observable.OnSubscribe<Integer>() {  
  2.            @Override  
  3.            public void call(Subscriber<? super Integer> subscriber) {  
  4.                for (int i = 0; i < 10; i++) {  
  5.                    subscriber.onNext(i);  
  6.                }  
  7.            }  
  8.        }).subscribe(new Subscriber<Integer>() {  
  9.            @Override  
  10.            public void onCompleted() {  
  11.   
  12.            }  
  13.            @Override  
  14.            public void onError(Throwable t) {  
  15.   
  16.            }  
  17.            @Override  
  18.            public void onNext(Integer var1) {  
  19.                System.out.println(var1);  
  20.            }  
  21.        });  

添加操作符

其实,强大的RxJava的核心原理并没有想象中那么复杂和神秘,运用的就是典型的观察者模式。有了基本雏形之后,我们继续为这个框架添砖加瓦吧。RxJava之所以强大好用,与其拥有丰富灵活的操作符是分不开的。那么我们就试着为这个框架添加一个最常用的操作符:map。

那么RxJava是如何实现操作符的呢?其实,每调用一次操作符的方法,就相当于在上层数据源和下层观察者之间桥接了一个新的Observable。桥接的Observable内部会实例化有新的OnSuscribe和Subscriber。OnSuscribe负责接受目标Subscriber传来的订阅请求,并调用源Observable.OnSubscribe的subscribe方法。源Observable.OnSubscribe将Event往下发送给桥接Observable.Subscriber,最终桥接Observable.Subscriber将Event做相应处理后转发给目标Subscriber。流程如下图所示:

这里写图片描述

接着,我们用代码实现这一过程。在Observable类里面添加如下代码:

[java] view plain copy

  1. public <R> Observable<R> map(Transformer<? super T, ? extends R> transformer) {  
  2.         return create(new OnSubscribe<R>() { // 生成一个桥接的Observable和 OnSubscribe  
  3.             @Override  
  4.             public void call(Subscriber<? super R> subscriber) {  
  5.                 Observable.this.subscribe(new Subscriber<T>() { // 订阅上层的Observable  
  6.                     @Override  
  7.                     public void onCompleted() {  
  8.                         subscriber.onCompleted();  
  9.                     }  
  10.                     @Override  
  11.                     public void onError(Throwable t) {  
  12.                         subscriber.onError(t);  
  13.                     }  
  14.                     @Override  
  15.                     public void onNext(T var1) {  
  16.                         // 将上层的onSubscribe发送过来的Event,通过转换和处理,转发给目标的subscriber  
  17.                         subscriber.onNext(transformer.call(var1));  
  18.                     }  
  19.                 });  
  20.             }  
  21.         });  
  22.     }  
  23.     public interface Transformer<T, R> {  
  24.         R call(T from);  
  25.     }  

map操作符的作用是将T类型的Event转化成R类型,转化策略抽象成Transformer<T, R>(RxJava中用的是Func1<T, R>,但为了便于理解,起了一个有意义的名字)这一个函数接口,由外部传入。

上面代码中使用到一些泛型的通配符,有些地方使用了super,有些地方使用了extends,其实这是有讲究的,传给Transformer#call方法的参数是T类型的,那么call方法的参数类型可以声明成是T的父类,Transformer#call方法的返回值要求是R类型的,那么它的返回值类型应该声明成R的子类。如果大家不能理解,也可以不用在意这些细节。

那么我们一起来测试一下吧。

[java] view plain copy

  1. Observable.create(new Observable.OnSubscribe<Integer>() {  
  2.             @Override  
  3.             public void call(Subscriber<? super Integer> subscriber) {  
  4.                 for (int i = 0; i < 10; i++) {  
  5.                     subscriber.onNext(i);  
  6.                 }  
  7.             }  
  8.         }).map(new Observable.Transformer<Integer, String>() {  
  9.             @Override  
  10.             public String call(Integer from) {  
  11.                 return "maping " + from;  
  12.             }  
  13.         }).subscribe(new Subscriber<String>() {  
  14.             @Override  
  15.             public void onNext(String var1) {  
  16.                 System.out.println(var1);  
  17.             }  
  18.             @Override  
  19.             public void onCompleted() {}  
  20.             @Override  
  21.             public void onError(Throwable t) {}  
  22.         });  

但是,我们看到map()方法内内部类有点多,代码缺少拓展性和可读性,我们应该进行适当地重构,将主要的逻辑抽离成独立的模块,并保证模块间尽量解耦,否则Observable只会越来越臃肿。

[java] view plain copy

  1. public <R> Observable<R> map(Transformer<? super T, ? extends R> transformer) {  
  2.         return create(new MapOnSubscribe<T, R>(this, transformer));  
  3.     }  
  4. public class MapOnSubscribe<T, R> implements Observable.OnSubscribe<R> {  
  5.     final Observable<T> source;  
  6.     final Observable.Transformer<? super T, ? extends R> transformer;  
  7.     public MapOnSubscribe(Observable<T> source, Observable.Transformer<? super T, ? extends R> transformer) {  
  8.         this.source = source;  
  9.         this.transformer = transformer;  
  10.     }  
  11.     @Override  
  12.     public void call(Subscriber<? super R> subscriber) {  
  13.         source.subscribe(new MapSubscriber<R, T>(subscriber, transformer));  
  14.     }  
  15. }  
  16. public class MapSubscriber<T, R> extends Subscriber<R> {  
  17.     final Subscriber<? super T> actual;  
  18.     final Observable.Transformer<? super R, ? extends T> transformer;  
  19.     public MapSubscriber(Subscriber<? super T> actual, Observable.Transformer<? super R, ? extends T> transformer) {  
  20.         this.actual = actual;  
  21.         this.transformer = transformer;  
  22.     }  
  23.     @Override  
  24.     public void onCompleted() {  
  25.         actual.onCompleted();  
  26.     }  
  27.     @Override  
  28.     public void onError(Throwable t) {  
  29.         actual.onError(t);  
  30.     }  
  31.     @Override  
  32.     public void onNext(R var1) {  
  33.         actual.onNext(transformer.call(var1));  
  34.     }  
  35. }  

添加线程切换功能

RxJava中最激动人心的功能是异步处理,能够自如地切换线程。利用 subscribeOn() 结合 observeOn() 来实现线程控制,让事件的产生和消费发生在不同的线程。 observeOn() 可以多次调用,实现了线程的多次切换,最终目标Subscriber的执行线程与最后一次observeOn()的调用有关。但subscribeOn() 多次调用只有第一个subscribeOn() 起作用。为什么呢?因为 observeOn() 作用的是Subscriber,而subscribeOn() 作用的是OnSubscribe。

这里借用扔物线的图:

这里写图片描述

简单地调用一个方法就可以完成线程的切换,很神奇对吧。RxJava是如何实现的呢?除了桥接Observable以外,RxJava还用到一个很关键的类—Scheduler(调度器)。文档中给Scheduler的定义是:A Scheduler is an object that schedules units of work.,也就是进行任务的调度的一个东西。Scheduler里面有一个重要的抽象方法:

[java] view plain copy

  1. public abstract Worker createWorker();  

Worker是Scheduler的内部类,它是具体任务的执行者。当要提交任务给Worker执行需要调用Worker的schedule(Action0 aciton)方法。

[java] view plain copy

  1. public abstract Subscription schedule(Action0 action);  

要获得一个Scheduler并不需要我们去new,一般是调用Schedulers的工厂方法。

[java] view plain copy

  1. public final class Schedulers {  
  2.     private final Scheduler computationScheduler;  
  3.     private final Scheduler ioScheduler;  
  4.     private final Scheduler newThreadScheduler;  
  5.     public static Scheduler io() {  
  6.         return RxJavaHooks.onIOScheduler(getInstance().ioScheduler);  
  7.     }  
  8.     public static Scheduler computation() {  
  9.         return RxJavaHooks.onComputationScheduler(getInstance().computationScheduler);  
  10.     }  
  11.   ...  
  12. }  

具体的Scheduler的实现类就不带大家一起看了,但我们需要知道,能做到线程切换的关键Worker的schedule方法,因为它会把传过来的任务放入线程池,或新线程中执行,这取决于具体Scheduler的实现。

自定义Scheduler

那么,下面我们先来自定义一个简单的Scheduler和Worker。

[java] view plain copy

  1. public class Scheduler {  
  2.     final Executor executor;  
  3.     public Scheduler(Executor executor) {  
  4.         this.executor = executor;  
  5.     }  
  6.     public Worker createWorker() {  
  7.         return new Worker(executor);  
  8.     }  
  9.     public static class Worker {  
  10.         final Executor executor;  
  11.         public Worker(Executor executor) {  
  12.             this.executor = executor;  
  13.         }  
  14.       // 这里接受的是Runnable而不是Action0,其实这没什么关系,主要是懒得自定义函数式接口了。  
  15.         public void schedule(Runnable runnable) {  
  16.             executor.execute(runnable);  
  17.         }  
  18.     }  
  19. }  

为了达到高仿效果,我们也提供相应的工厂方法。

[java] view plain copy

  1. public class Schedulers {  
  2.     private static final Scheduler ioScheduler = new Scheduler(Executors.newSingleThreadExecutor());  
  3.     public static Scheduler io() {  
  4.         return ioScheduler;  
  5.     }  
  6. }  

实现subscribeOn

subscribeOn是作用于上层OnSubscribe的,可以让OnSubscribe的call方法在新线程中执行。

因此,在Observable类里面,添加如下代码:

[java] view plain copy

  1. public Observable<T> subscribeOn(Scheduler scheduler) {  
  2.         return Observable.create(new OnSubscribe<T>() {  
  3.             @Override  
  4.             public void call(Subscriber<? super T> subscriber) {  
  5.                 subscriber.onStart();  
  6.                 // 将事件的生产切换到新的线程。  
  7.                 scheduler.createWorker().schedule(new Runnable() {  
  8.                     @Override  
  9.                     public void run() {  
  10.                         Observable.this.onSubscribe.call(subscriber);  
  11.                     }  
  12.                 });  
  13.             }  
  14.         });  
  15.     }  

测试一下:

[java] view plain copy

  1. Observable.create(new Observable.OnSubscribe<Integer>() {  
  2.             @Override  
  3.             public void call(Subscriber<? super Integer> subscriber) {  
  4.                 System.out.println("OnSubscribe@ "+Thread.currentThread().getName()); //new Thread  
  5.                 subscriber.onNext(1);  
  6.             }})  
  7.                 .subscribeOn(Schedulers.io())  
  8.                 .subscribe(new Subscriber<Integer>() {  
  9.                   ...  
  10.                     @Override  
  11.                     public void onNext(Integer var1) {  
  12.                         System.out.println("Subscriber@ "+Thread.currentThread().getName()); // new Thread  
  13.                         System.out.println(var1);  
  14.                     }  
  15.                 });  

实现observeOn

subscribeOn是作用于下层Subscriber的,需要让下层Subscriber的事件处理方法放到新线程中执行。

为此,在Observable类里面,添加如下代码:

[java] view plain copy

  1. public Observable<T> observeOn(Scheduler scheduler) {  
  2.         return Observable.create(new OnSubscribe<T>() {  
  3.             @Override  
  4.             public void call(Subscriber<? super T> subscriber) {  
  5.                 subscriber.onStart();  
  6.                 Scheduler.Worker worker = scheduler.createWorker();  
  7.                 Observable.this.onSubscribe.call(new Subscriber<T>() {  
  8.                     @Override  
  9.                     public void onCompleted() {  
  10.                         worker.schedule(new Runnable() {  
  11.                             @Override  
  12.                             public void run() {  
  13.                                 subscriber.onCompleted();  
  14.                             }  
  15.                         });  
  16.                     }  
  17.                     @Override  
  18.                     public void onError(Throwable t) {  
  19.                         worker.schedule(new Runnable() {  
  20.                             @Override  
  21.                             public void run() {  
  22.                                 subscriber.onError(t);  
  23.                             }  
  24.                         });  
  25.                     }  
  26.                     @Override  
  27.                     public void onNext(T var1) {  
  28.                         worker.schedule(new Runnable() {  
  29.                             @Override  
  30.                             public void run() {  
  31.                                 subscriber.onNext(var1);  
  32.                             }  
  33.                         });  
  34.                     }  
  35.                 });  
  36.             }  
  37.         });  
  38.     }  

测试一下:

[java] view plain copy

  1. Observable.create(new Observable.OnSubscribe<Integer>() {  
  2.             @Override  
  3.             public void call(Subscriber<? super Integer> subscriber) {  
  4.                 System.out.println("OnSubscribe@ " + Thread.currentThread().getName()); // main  
  5.                 subscriber.onNext(1);  
  6.             }  
  7.         })  
  8.                 .observeOn(Schedulers.io())  
  9.                 .subscribe(new Subscriber<Integer>() {  
  10.                   ...  
  11.                     @Override  
  12.                     public void onNext(Integer var1) {  
  13.                         System.out.println("Subscriber@ " + Thread.currentThread().getName()); // new Thread  
  14.                         System.out.println(var1);  
  15.                     }  
  16.                 });  

在Android中切换线程

经过以上实践,我们终于知道了RxJava线程切换的核心原理了。下面我们顺便来看看Android里面是如何进行线程切换的。

首先找到AndroidSchedulers,发现一个Scheduler的具体实现类:LooperScheduler。

[java] view plain copy

  1. private AndroidSchedulers() {  
  2.     ...  
  3.             mainThreadScheduler = new LooperScheduler(Looper.getMainLooper());  
  4.             ...  
  5.     }  
  6.     /** A {@link Scheduler} which executes actions on the Android UI thread. */  
  7.     public static Scheduler mainThread() {  
  8.         return getInstance().mainThreadScheduler;  
  9.     }  

LooperScheduler的代码很清晰,内部持有一个Handler,用于线程的切换。在Worker的schedule(Action0 action,...)方法中,将action通过Handler切换到所绑定的线程中执行。

[java] view plain copy

  1. class LooperScheduler extends Scheduler {  
  2.     private final Handler handler;  
  3.   
  4.     LooperScheduler(Looper looper) {  
  5.         handler = new Handler(looper);  
  6.     }  
  7.   
  8.     LooperScheduler(Handler handler) {  
  9.         this.handler = handler;  
  10.     }  
  11.   
  12.     @Override  
  13.     public Worker createWorker() {  
  14.         return new HandlerWorker(handler);  
  15.     }  
  16.   
  17.     static class HandlerWorker extends Worker {  
  18.         private final Handler handler;  
  19.   
  20.       ...  
  21.   
  22.         @Override  
  23.         public Subscription schedule(Action0 action, long delayTime, TimeUnit unit) {  
  24.         ...  
  25.             action = hook.onSchedule(action);  
  26.   
  27.             ScheduledAction scheduledAction = new ScheduledAction(action, handler);  
  28.   
  29.             Message message = Message.obtain(handler, scheduledAction);  
  30.             message.obj = this; // Used as token for unsubscription operation.  
  31.   
  32.             handler.sendMessageDelayed(message, unit.toMillis(delayTime));  
  33.         ...  
  34.             return scheduledAction;  
  35.         }  
  36.   
  37.         @Override  
  38.         public Subscription schedule(final Action0 action) {  
  39.             return schedule(action, 0, TimeUnit.MILLISECONDS);  
  40.         }  
  41.     }  
  42.   
  43.     static final class ScheduledAction implements Runnable, Subscription {  
  44.         private final Action0 action;  
  45.         private final Handler handler;  
  46.         private volatile boolean unsubscribed;  
  47.       ...  
  48.         @Override public void run() {  
  49.             try {  
  50.                 action.call();  
  51.             } ...  
  52.         }  
  53.         ...  
  54.     }  
  55. }  

结语

就这样,以上用代码演示了RxJava一些核心功能是如何实现的,希望能给大家带来不一样的启发。但这只是一个小小的Demo,离真正能运用于工程的Rx框架还差太远。这也让我们明白到,一个健壮的框架,需要考虑太多东西,比如代码的可拓展性和可读性,性能优化,可测试性,兼容性,极端情况等等。但有时要想深入理解一个复杂框架的实现原理,就需要剥离这些细节代码,多关注主干的调用逻辑,化繁为简。

Demo代码可到Github获取:https://github.com/TellH/RxJavaDemo/tree/master/src/my_rxjava

参考&拓展

猜你喜欢

转载自my.oschina.net/sfshine/blog/1809921