RxJava切换线程是怎么实现的呢?

RxJava切换线程是怎么实现的呢?

lift变换过程

要明白 RxJava 切换线程切换线程的原理,我们首先得理解变换过程。
对于变换过程,我的理解就是:

Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            subscriber.onNext("Hello");
            subscriber.onNext("Hi");
            subscriber.onNext("Aloha");
            subscriber.onCompleted();
        }
      })
      .observeOn(Schedulers.io())

      .map(new Function<String, List<String>>() {
        @Override
        public List<String> apply(String query) {
          return mCheeseSearchEngine.search(query);
        }
      })
      .observeOn(AndroidSchedulers.mainThread())

      .subscribe(new Consumer<List<String>>() {
        @Override
        public void accept(List<String> result) {
          showResult(result);
        }
      });

在上面的代码中,map 过程通过它的 apply 方法中把 String 转换为 List\ ,而这一点是 subscribe 无法做到的。

public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {
    return lift(new OperatorMap<T, R>(func)); 
}

通过 map函数 的源码我们可以看出 map 函数直接调用了 lift 函数并且把我们的 func 传了进去,而 func 就是我们所做的具体变换操作。

// 注意:这段代码被我修改过部分参数,仅用于理解,源码并非如此。
public <R> Observable<R> lift(Operator<? extends R, ? super T> operator) {
    return Observable2.create(new OnSubscribe2<R>() {
        @Override
        public void call(Subscriber subscriber1) {
            Subscriber subscriber2 = operator.call(subscriber1);
            subscriber2.onStart();
            onSubscribe1.call(subscriber2);
        }
    });
}

我们可以看到这里我们又创建了一个新的 Observable 对象,我们记为 Observable2,也就是说当我们执行 map 时,实际上返回了一个新的 Observable 对象,我们之后的 subscribe 函数实际上执行再我们新创建的 Observable2 上,这时他调用的就是我们新的 call 函数,也就是 Observable2 的 call 函数。最后 onSubscribe1.call(subscriber2) 的 onSubscribe1 就是我们 Observable1(原来的Observable) 保存的 onSubscribe1 对象,在OnSubscrib1中做一些回调操作,如subscriber2.next()。

接着我们看operator.call(subscriber1)的过程。

// 注意:这段代码也被我修改过。
public Subscriber<? super T> call(final Subscriber<? super R> subscriber1) { 
    return new Subscriber2<T>(subscriber1) {
        @Override
        public void onNext(T t) {
            subscriber1.onNext(transformer.call(t)); 
        }
    };
}

这里的 transformer 就是我们在 map 调用是传进去的 func 函数,也就是变换的具体过程。到这里变换过程就此结束。我们总结一下,


如图所示,实际上我们通过 lift 创建了一个新的对象 Observable2 ,我们之后的 subscribe 实际上执行在了它身上。operator执行了之前 Observable1 的 call 函数,并且创建了一个新的对象 Subscriber2 ,它的作用就是接受原来 Observable1 的事件 func ,然后经过转换,传递给最终的 Subscriber1,执行它的 onNext 函数。我们这样就跑通了变换的整个逻辑了,我们也可以发现这个逻辑类似于拦截,通过拦截 subscribe 函数,再把 Observable1 的 subscribe 拦截到新的 Subscriber2 对象中来执行,从而实现转换的逻辑。

线程切换

RxJava 最好用的特点就是��供了方便的线程切换,但它的原理归根结底还是 lift。subscribeOn() 和 observeOn() 都做了线程切换的工作(图中的 “schedule…” 部位)。不同的是, subscribeOn() 的线程切换发生在 OnSubscribe 中,即在它通知上一级 OnSubscribe 时,这时事件还没有开始发送,因此 subscribeOn() 的线程控制可以从事件发出的开端就造成影响。

subscribeOn() 原理图

observeOn() 原理图

为什么 subscribeOn()只有第一个有效?

举个例子,subscribeOn2从通知开始将后面的执行全部投递到需要的线程2来执行,但是之后的投递会受到在subscribeOn2的上级subscribeOn1的的影响,subscribeOn1又会把执行投递到线程1中去,这样执行就不受到subscribeOn2的控制了。所以只有第一个subscribeOn有效。

图中共有 5 处含有对事件的操作。由图中可以看出,①和②两处受第一个 subscribeOn() 影响,运行在红色线程;③和④处受第一个 observeOn() 的影响,运行在绿色线程;⑤处受第二个 onserveOn() 影响,运行在紫色线程;而第二个 subscribeOn() ,由于在通知过程中线程就被第一个 subscribeOn() 截断,因此对整个流程并没有任何影响。这里也就回答了前面的问题:当使用了多个 subscribeOn() 的时候,只有第一个 subscribeOn() 起作用。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值