RxJava(十五)RxJava 线程的自由切换

15 篇文章 42 订阅

RxJava 系列文章目录导读:

一、RxJava create 操作符的用法和源码分析
二、RxJava map 操作符用法详解
三、RxJava flatMap 操作符用法详解
四、RxJava concatMap 操作符用法详解
五、RxJava onErrorResumeNext 操作符实现 app 与服务器间 token 机制
六、RxJava retryWhen 操作符实现错误重试机制
七、RxJava 使用 debounce 操作符优化 app 搜索功能
八、RxJava concat 操作处理多数据源
九、RxJava zip 操作符在 Android 中的实际使用场景
十、RxJava switchIfEmpty 操作符实现 Android 检查本地缓存逻辑判断
十一、RxJava defer 操作符实现代码支持链式调用
十二、combineLatest 操作符的高级使用
十三、RxJava 导致 Fragment Activity 内存泄漏问题
十四、interval、takeWhile 操作符实现获取验证码功能
十五、RxJava 线程的自由切换


在 Android 使用 RxJava 的时候可能需要频繁的进行线程的切换,如耗时操作放在子线程中执行,执行完后在主线程渲染界面。如下面示例代码:

deferObservable(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //执行耗时任务
                return "task result";
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                //渲染View
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                throwable.printStackTrace();
            }
        });

这是最简单的逻辑:子线程处理耗时任务,然后处理结果。
但是在实际的开发当中可能比这个更加复杂,比如有这样的逻辑,先从本地加载数据(子线程),然后界面展示本地数据(主线程),接着加载线上数据(子线程),然后渲染(主线程)。这就需要频繁的切换线程。

RxJava 中通过 subscribeOnobserveOn 两个操作符进行线程切换。subscribeOn() 主要改变的是订阅的线程,即 call() 执行的线程,observeOn() 主要改变的是发送的线程,即 onNext() 执行的线程。

为了实现上面自由切换的逻辑(子线程 -> 主线程 -> 子线程 -> 主线程)

deferObservable(new Callable<String>() { //defer observable
            @Override
            public String call() throws Exception {
                Log.d("RxThreadFragment", "defer " + Thread.currentThread().getName());
                return "task result";
            }
        })
        .observeOn(AndroidSchedulers.mainThread())//指定下面的 call 在主线程中执行
        .flatMap(new Func1<String, Observable<String>>() {
            @Override
            public Observable<String> call(String s) {
                Log.d("RxThreadFragment", "flatMap1 " + Thread.currentThread().getName());
                return Observable.just(s);
            }
        })
        .observeOn(Schedulers.io())//指定下面的 call  在子线程中执行
        .flatMap(new Func1<String, Observable<String>>() {
            @Override
            public Observable<String> call(String s) {
                Log.d("RxThreadFragment", "flatMap2 " + Thread.currentThread().getName());
                return Observable.just(s);
            }
        })
        .subscribeOn(Schedulers.io())//指定上面没有指定所在线程的Observable在IO线程执行
        .observeOn(AndroidSchedulers.mainThread())//指定下面的 call  在主线程中执行
        .subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                //etc
                Log.d("RxThreadFragment", s + Thread.currentThread().getName());
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                throwable.printStackTrace();
            }
        });

输出结果:

defer RxIoScheduler-2
flatMap2 main
flatMap3 RxIoScheduler-3
task result main

从上面的代码可以看出,observeOn 指定该操作符下面相邻的 Observable 发射数据所在的线程。
subscribeOn 指定该操作符上面所有没有指定线程的 Observable 所在的线程。
例如在刚刚的例子中,subscribeOn 操作符上面有 3 个observable(“defer”、“flatMap1”、“flatMap2”)
由于 flatMap1, flatMap2 已经分别被 observeOn 指定了 schedule 了,所以呢,该subscribeOn只会对 “defer” 有效。

下面我们再来看一个例子

final Observable<String> observable1 = RxUtils.deferObservable(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Log.e("RxThreadFragment", "observable1 thread name : " + Thread.currentThread().getName());
                return "observable1 Schedulers.io()";
            }
        }).subscribeOn(Schedulers.io());//指定上面call方法所在的线程

        final Observable<String> observable2 = RxUtils.deferObservable(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Log.e("RxThreadFragment", "observable2 thread name : " + Thread.currentThread().getName());
                return "observable2 AndroidSchedulers.mainThread()";
            }
        }).subscribeOn(Schedulers.io());//指定上面call方法所在的线程

        final Observable<String> observable3 = RxUtils.deferObservable(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Log.e("RxThreadFragment", "observable3 thread name : " + Thread.currentThread().getName());
                return "observable3 Schedulers.io()";
            }
        }).subscribeOn(Schedulers.io());//指定上面call方法所在的线程

        RxUtils.deferObservable(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        Log.e("RxThreadFragment", "test thread name : " + Thread.currentThread().getName());
                        return "test thread";
                    }
                })
                .subscribeOn(Schedulers.io())//修改上面Observable call所在的线程
                .observeOn(AndroidSchedulers.mainThread())//修改下面flatMap1 call所在的线程
                .flatMap(new Func1<String, Observable<String>>() {//flatMap1
                    @Override
                    public Observable<String> call(String s) {
                        Log.e("RxThreadFragment", "flatMap1 thread name : " + Thread.currentThread().getName());
                        return observable1;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())//修改下面flatMap2 call所在的线程
                .flatMap(new Func1<String, Observable<String>>() {//flatMap2
                    @Override
                    public Observable<String> call(String s) {
                        Log.e("RxThreadFragment", "flatMap2 thread name : " + Thread.currentThread().getName());
                        return observable2;
                    }
                })
                .flatMap(new Func1<String, Observable<String>>() {
                    @Override
                    public Observable<String> call(String s) {
                        Log.e("RxThreadFragment", "flatMap3 thread name : " + Thread.currentThread().getName());
                        return observable3;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())//修改下面subscribe call所在的线程
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        Log.e("RxThreadFragment", "subscribe Action1 thread name : " + Thread.currentThread().getName());
                    }
                }, new Action1<Throwable>() {
                    @Override
                    public void call(Throwable throwable) {
                        throwable.printStackTrace();
                    }
                });

输出结果:

test thread name : RxIoScheduler-2              手动设置为后台线程
flatMap1 thread name : main                     手动设置为主线程
observable1 thread name : RxIoScheduler-3       手动设置为后台线程
flatMap2 thread name : main                     手动设置为主线程
observable2 thread name : RxIoScheduler-2       手动设置为后台线程
flatMap3 thread name : RxIoScheduler-2          后台线程
observable3 thread name : RxIoScheduler-3       手动设置为后台线程
subscribe Action1 thread name : main            手动设置为主线程

从这个例子中可以看出,flatMap3 没有设置所在的线程,会默认使用上一个 observable的线程模式, flatMap3 就是使用它上面的 observable2 的线程模式
如果上一个操作符不是 flatMap,而是使用 map (这样就不是返回 observable2),这个时候使用的就是 map call 所在的线程。

通过上面两个例子我相信对 RxJava 线程切换应该差不多了,需要注意的是我们上面基本上都是一个 subscribeOn 和多个 observeOn 组合实现线程的自由切换的。

如果使用多个 subscribeOn 没有意义,只有第一个 subscribeOn 有效。

本文 GitHub 源代码: https://github.com/chiclaim/AndroidAll


如果你觉得本文帮助到你,给我个关注和赞呗!

另外,我为 Android 程序员编写了一份:超详细的 Android 程序员所需要的技术栈思维导图

如果有需要可以移步我的 GitHub -> AndroidAll,里面包含了最全的目录和对应知识点链接,帮你扫除 Android 知识点盲区。 由于篇幅原因只展示了 Android 思维导图:
超详细的Android技术栈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chiclaim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值