RxJava 系列八:Map 变换原理

99 阅读3分钟

RxJava 系列八:Map 变换原理

  • 本文概述:

    • 文章以RxJava 重要拦截器map 为主题,以源码分析为目的;系统展示了map的源码执行流程,探讨了 map 的工作原理;并在文章末尾总结了拆包、解包流程;

Map干了什么

  • 做类型变换:例如向map输入String类型事件,map输出 BitMap类型事件

代码分析:

  • 代码展示

     // 返回ObservableCreate对象,并且将自定义source传进去
     Observable.create(
     ​
         //下面这一块就是自定义source
         new ObservableOnSubscribe<String>() {
             @Override
             public void subscribe(ObservableEmitter<String> e) throws Exception {
     ​
             }
         })
     ​
         //  由ObseravbleCreate.map执行
         .map(new Function<String, Bitmap>() {
             @Override
             public Bitmap apply(String s) throws Exception {
                 return null;
             }
         })
     ​
         // 由ObservableMap.subscribe 执行
         .subscribe(
     ​
             // 自定义观察者(事件流向的终点)
             new Observer<Bitmap>() {
                 @Override
                 public void onSubscribe(Disposable d) {
     ​
                 }
     ​
                 @Override
                 public void onNext(Bitmap bitmap) {
     ​
                 }
     ​
                 @Override
                 public void onError(Throwable e) {
     ​
                 }
     ​
                 @Override
                 public void onComplete() {
     ​
                 }
             });
    

流程是怎么玩的?

  • 示意图:U型结构

图片.png

  • 第一次跳转:进入Observable.subscribe

    • 将终点作为参数,传入订阅流程;Observable.subscribe 中调用 subscribeActual(observer);
  • 第二次跳转:进入ObservableMap.subscribeActual();

    • 这个是抽象函数,那么执行到其实现类中重写,执行到 ObservableMap.subscribeActual();

    • 封装第一级包裹,将包裹拿给map的上一层(ObservableCreate)

       @Override
       public void subscribeActual(Observer<? super U> t) {
           source.subscribe(new MapObserver<T, U>(t, function));
       }
      
    • 细节:这里的 source 不是业务代码中的自定义 source 而是事件流动中的 Map 卡片的上一事件

       public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
           super(source);
           this.function = function;
       }
      
  • 第三次跳转:进入ObservableCreate.subscribeActual();

    • 以第一级包裹为参数封装第二级包裹

       @Override
       protected void subscribeActual(Observer<? super T> observer) {
           CreateEmitter<T> parent = new CreateEmitter<T>(observer);
      
    • 此时会触发终点处的重写订阅

    • 通过业务代码中的自定义source.subscribe(parent),

       //参数是第二级包裹
       observer.onSubscribe(parent);
      
    • 此时的 source 才是业务代码中的 自定义 source

       public ObservableCreate(ObservableOnSubscribe<T> source) {
           this.source = source;
       }
      
  • 第四次跳转:进入source.onNext()

  • 第五次跳转:进入第二级包裹的 onNext

     @Override
     public void onNext(T t) {
         if (t == null) {
             onError(new NullPointerException("XXX"));
             return;
         }
         if (!isDisposed()) {
             //进入第一级包裹的 onNext()
             observer.onNext(t);
         }
     }
    
  • 第六次跳转:进入第一级包裹的 onNext

    • 在这个里面做变换(T 是输入事件,R 是输出类型)

    • 重点在这个地方:mapper.apply(t)

      • 这里涉及一个接口
       //T: map的输入事件,map的输出事件
       public interface Function<T, R> {
           R apply(@NonNull T t) throws Exception;
       }
      
      • 真正的实现:在业务代码中的map卡片里面
       //业务代码中的map卡片(由用户指定了事件的输入输出)
       .map(new Function<String, Bitmap>() {
           @Override
           public Bitmap apply(String s) throws Exception {
               return null;
           }
       })
      

      第一级包裹的 onNext

     @Override
     public void onNext(T t) {
         if (done) {
             return;
         }
     ​
         if (sourceMode != NONE) {
             actual.onNext(null);
             return;
         }
     ​
         U v;
     ​
         try {
             v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
         } catch (Throwable ex) {
             fail(ex);
             return;
         }
         actual.onNext(v);
     }
    
  • 第六次跳转细节:mapper实际上就是终点,map<T,R> 中的R 就是终点.onNext(t) 里面的 t

    • 源码展示:为什么是这样
     //返回的是R,意味着经过 map 卡片后输出的事件类型就是 R,那么终点.onNext(t)就是R
     @CheckReturnValue
     @SchedulerSupport(SchedulerSupport.NONE)
     public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
         ObjectHelper.requireNonNull(mapper, "mapper is null");
         return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
     }
    
  • 重点代码展示: ObservableMap.subscribeActual

    • 将终点传入,此时做了一层包裹,向下走开始拆包裹(典型的洋葱模型)

    • 这个source是map的上一层:ObservableCreate

    • 源码展示

      image-20220629222840362

  • 重点代码展示: ObservableCreate.subscribeActual()

    • 将第一级包裹作为参数,封装了第二级包裹parent(实际上就是发射器)

    image-20220629223352952

封包与拆包:

  • 封包裹是为了拆包裹

  • 封包与拆包:

    • 向上走(黑色):封包
    • 向下走(红色):拆包

    封包拆包

  • 好看的图片:

    Map

  • 写了多少个 map 就会封多少次,拆多少次

  • 为什么要这样写?

    • 确保 Rx 编程的实现:可以保证思维不断的情况下,从起点到终点添加无数张卡片

补充:装饰模型

  • 不断给它穿衣服:

    • 流程是从上往下走

装饰模型

  • 这种才是最正确的RxJava 结构

图片.png