Rxjava observeOn()和subscribeOn()初探

Rxjava这么强大的类库怎么可能没有多线程切换呢?

其中observeOn()与subscribeOn()就是实现这样的作用的。本文主要讲解observeOn()与subscribeOn()的用法,不去探究其中的原理。

0. 默认情况

在默认情况下,其不做任何线程处理,Observable和Observer处于同一线程,没有做任何线程切换,依次执行,如下图所示:

可以写一个demo测试之:

Observable<String> source = Observable.just("Alpha","Beta","Gamma");
        source.subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(Integer integer) {
                    Log.i("TAG", "Received " + integer + " on thread:" +
                    Thread.currentThread().getName());
            }
        });

1. subscribeOn()的作用

该方法是指明数据产生的线程,即Observable发射数据所在的线程,如果之后不做任何处理,操作符operator(如map,flatmap等)也在subscribeOn指定的线程做数据处理。

多次使用subscribeOn()并不能频繁地切换线程,只有距离数据源最近的一个subscribeOn()唯一确定数据源发射数据的线程。如代码所示:

Observable<String> source = Observable.just("Alpha","Beta","Gamma");
source
.subscribeOn(Schedulers.computation())
.subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(Integer integer) {
                    Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
            }
        });
    }

其中只有subscribeOn(Schedulers.computation())对数据源source起作用,该source在Schedulers.computation()指定的线程发射数据。如果后面没有使用observeOn(),操作符operator都会在Schedulers.computation()所指定的线程做数据变换。

2. observeOn()的作用

在Android开发中,我们经常面临这样的场景,在工作者线程中产生数据,在UI线程中更新相应的View,subscribeOn()指定了数据发射的线程,但我们更新UI的操作,不可能在发射数据的线程运行,这会造成ANR的问题。此时就必须通过observeOn()方法做线程的切换:

Observable<String> source = Observable.just("Alpha","Beta","Gamma");
        source.map(new Func1<String, Integer>() {
            @Override
            public Integer call(String s) {
                Log.i("TAG", "call: " + Thread.currentThread().getName());
                return s.length();
            }
        }).observeOn(Schedulers.newThread()).subscribeOn(Schedulers.computation()).
                subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
            }

            @Override
            public void onNext(Integer integer) {
                    Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
            }
        });

上述代码的运行结果如下:

TAG: call: RxComputationScheduler-1
TAG: onNext: on thread:RxNewThreadScheduler-1
TAG: call: RxComputationScheduler-1
TAG: onNext: on thread:RxNewThreadScheduler-1
TAG: call: RxComputationScheduler-1
TAG: onNext: on thread:RxNewThreadScheduler-1

可以看到,在observeOn()之前的操作,都运行在subscribeOn(Schedulers.computation())指定的线程,即RxComputationScheduler-1线程;而使用了observeOn()之后,在它之后的操作都

运行在了observeOn(Schedulers.newThread())指定的线程。

所以,给出一个结论observeOn()只对其之后的操作起作用;observeOn()可以使用多次,每次使用对其之后的operator起作用,对之前的操作没有影响。

上图很好地诠释了ObserveOn的作用。

3. backpressure的问题

由于ObserveOn的作用,数据流在多个线程中不断的传输,可能存在速度不匹配的情况。如下图所示,当底部的数据流发射速度快于顶部数据流的处理速度,若产生异常,可能导致一部分数据未被顶部的subscriber处理。

废话太多,说不清楚,看下代码吧:

Observable<String> source = Observable.just("Alpha","Beta","Gamma");
        source.map(new Func1<String, Integer>() {
            @Override
            public Integer call(String s) {
                Log.i("TAG", "call: " + Thread.currentThread().getName());
                if (s.equals("Gamma"))
                    throw new RuntimeException();
                return s.length();
            }
        })
         .doOnError(new Action1<Throwable>() {
             @Override
             public void call(Throwable throwable) {
                  Log.i("TAG", "doOnError: " + Thread.currentThread().getName());
             }
         })
        .observeOn(Schedulers.newThread())
        .subscribeOn(Schedulers.computation())
        .subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {
                Log.i("TAG", "onError: " + "on thread:" + Thread.currentThread().getName());
            }

            @Override
            public void onNext(Integer integer) {
                    Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
            }
        });
    }

看一下运行结果:

TAG: call: RxComputationScheduler-1
TAG: call: RxComputationScheduler-1
TAG: call: RxComputationScheduler-1
TAG: doOnError: RxComputationScheduler-1
TAG: onError: on thread:RxNewThreadScheduler-1

我们就可以看到,当发射的数据为Gamma时抛出异常,之前发射的数据"Alpha","Beta"还未被subsriber的onNext方法处理,这就是backpressure问题。

4. onErrorResumeNext

onErrorResumeNext是错误恢复处理方法,当我们数据链中某个操作符抛出异常,此时会中断整个数据链,但我们想尝试恢复一下,这时可以使用

onErrorResumeNext。比如Android在过于频繁登录时,系统会弹出一个dialog(弹窗),让用户输入验证码,该逻辑就可以放在onErrorResumeNext中处理。

我们先看一段代码:

Observable<String> source = Observable.just("Alpha","Beta","Gamma");
        source.map(new Func1<String, Integer>() {
            @Override
            public Integer call(String s) {
                Log.i("TAG", "call: " + Thread.currentThread().getName());
                if (s.equals("Gamma"))
                    throw new RuntimeException();
                return s.length();
            }
        })
                .observeOn(Schedulers.newThread())
                .subscribeOn(Schedulers.computation())
                .onErrorResumeNext(new Func1<Throwable, Observable<? extends Integer>>() {
            @Override
            public Observable<? extends Integer> call(Throwable throwable) {
                return Observable.just(1000).map(new Func1<Integer, Integer>() {
                    @Override
                    public Integer call(Integer integer) {
                        Log.i("TAG", "call:onErrorResumeNext: "  +  Thread.currentThread().getName());
                        return integer;
                    }
                })
                .subscribeOn(Schedulers.computation());
            }
        })
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i("TAG", "onError: " + "on thread:" + Thread.currentThread().getName());
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.i("TAG", "onNext: " + "on thread:" + Thread.currentThread().getName());
                    }
                });

看上段代码中onErrorResumeNext的部分,为什么在onErrorResumeNext可以再次使用subscribeOn(),我的猜测(并没有看源码)可能是该段代码产生了新的数据源,所以可以使用subsribeOn()指定数据源发射数据的线程。

它的运行结果:

TAG: call: RxComputationScheduler-1
TAG: call: RxComputationScheduler-1
TAG: call: RxComputationScheduler-1
TAG: onNext: on thread:RxNewThreadScheduler-1
TAG: onNext: on thread:RxNewThreadScheduler-1
TAG: call:onErrorResumeNext: RxComputationScheduler-2
TAG: onNext: on thread:RxComputationScheduler-2

看运行结果在onErrorResumeNext方法中使用了subscribeOn(),线程切换到了RxComputationScheduler-2,在之后没有observeOn的情况下,最后一个onNext也运行在了RxComputationScheduler-2。很神奇!!!!!

时间: 2024-10-07 15:49:29

Rxjava observeOn()和subscribeOn()初探的相关文章

RxJava observeOn()与subscribeOn()的关系

observeOn和subscribeOn都是对observable的一种操作,区别就是subscribeOn改变了observable本身产生事件的schedule以及发出事件后相关处理事件的程序所在的schedule,而obseveron仅仅是改变了对发出事件后相关处理事件的程序所在的schedule. 或许你会问,这有多大的区别吗?的确是有的,比如说产生observable事件是一件费时可能会卡主线程的操作(比如说获取网络数据),那么subscribeOn就是你的选择,这样可以避免卡住主线

RxJava从入门到放弃---关于RxJava-入门必看

RxJava 到底是什么 RxJava 好在哪 API 介绍和原理简析 1. 概念:扩展的观察者模式 观察者模式 RxJava 的观察者模式 2. 基本实现 1) 创建 Observer 2) 创建 Observable 3) Subscribe (订阅) 4) 场景示例 a. 打印字符串数组 b. 由 id 取得图片并显示 3. 线程控制 -- Scheduler (一) 1) Scheduler 的 API (一) 2) Scheduler 的原理 (一) 4. 变换 1) API 2) 变

给 Android 开发者的 RxJava 详解

作者:扔物线 前言 我从去年开始使用 RxJava ,到现在一年多了.今年加入了 Flipboard 后,看到 Flipboard 的 Android 项目也在使用 RxJava ,并且使用的场景越来越多 .而最近这几个月,我也发现国内越来越多的人开始提及 RxJava .有人说『RxJava 真是太好用了』,有人说『RxJava 真是太难用了』,另外更多的人表示:我真的百度了也谷歌了,但我还是想问: RxJava 到底是什么? 鉴于 RxJava 目前这种既火爆又神秘的现状,而我又在一年的使用

深入浅出RxJava就这一篇就够了

前言: 第一次接触RxJava是在前不久,一个新Android项目的启动,在评估时选择了RxJava.RxJava是一个基于事件订阅的异步执行的一个类库.听起来有点复杂,其实是要你使用过一次,就会大概明白它是怎么回事了!为是什么一个Android项目启动会联系到RxJava呢?因为在RxJava使用起来得到广泛的认可,又是基于Java语言的.自然会有善于组织和总结的开发者联想到Android!没错,RxAndroid就这样在RxJava的基础上,针对Android开发的一个库.今天我们主要是来讲

RxJava(11-线程调度Scheduler)

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51821940 本文出自:[openXu的博客] 目录: 使用示例 subscribeOn原理 多次subscribeOn的情况 observeOn原理 调度器的种类 各种操作符的默认调度器 源码下载 ??RxJava中 使用observeOn和subscribeOn操作符,你可以让Observable在一个特定的调度器上执行,observeOn指示一个Observable在一个特定的调度器

Rxjava入门与使用

认识 rxjava RxJava是 ReactiveX 在JVM上的一个实现,ReactiveX使用Observable序列 组合异步和基于事件 的程序. Observable(观察者) 和 Subscriber(订阅者)是两个主要的类.在 RxJava 上,一个 Observable 是一个发出数据流或者事件的类,Subscriber 是一个对这些发出的 items (数据流或者事件)进行处理(采取行动)的类.一个 Observable 的标准流发出一个或多个 item,然后成功完成或者出错.

RxJava入门

项目小版本上线,抽空简单学习了下久仰大名的RxJava 一.引入 个人觉得rxjava的特点: 强大灵活的事件流处理(多线程/多事件/复合对象) 强大灵活优雅简洁的异步 链式调用 可自动Lambda化 实现:RxJava 是通过一种扩展的观察者模式来实现的 类比 类比 实际 实际 职责 演讲者 Button (可)被订阅者 (同右) (可)被观察者 Observable 决定什么时候触发事件以及触发怎样的事件 听众 OnClickListener 订阅者 Subscriber 观察者 Obser

RxJava 并发之线程调度

由于 Rx 目标是用在异步系统上并且 Rx 支持多线程处理,所以很多 Rx 开发者认为默认情况下 Rx 就是多线程的. 其实实际情况不是这样的,Rx 默认是单线程的. 除非你明确的指定线程,否则所有 onNext/onError/onCompleted 以及各个操作函数的调用都是在同一个线程中完成的.例如下面的示例: final BehaviorSubject<Integer> subject = BehaviorSubject.create(); subject.subscribe(i -&

理解 RxJava 的线程模型

来源:鸟窝, colobu.com/2016/07/25/understanding-rxjava-thread-model/ 如有好文章投稿,请点击 → 这里了解详情 ReactiveX是Reactive Extensions的缩写,一般简写为Rx,最初是LINQ的一个扩展,由微软的架构师Erik Meijer领导的团队开发,在2012年11月开源,Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流,Rx库支持.NET.JavaScript和C++,Rx近几年越来越