本文篇幅较长 建议收藏起来等时间空闲详细阅读
本篇文章主要是一份学习笔记
线程控制(切换/调度)
-
线程控制的作用: 指定被观察者(observable) 和observer(观察者)的工作线程类型
-
线程控制的背景: 在RxJava模型中,被观察者(observable)和观察者(observer)的工作线程=创建自身的线程
- 即若被观察者在主线程中被创建,那么他们的工作就会发生在主线程
- 因为创建被观察者/观察者的线程=主线程
- 所以产生时间/接受&响应事件都发生在主线程
-
线程控制冲突:
- 对于一般的需求场景,需要在子线程中实现耗时操作,然后回到主线程实现UI操作
- 被观察者在子线程中产生事件(如实现耗时操作)
- 观察者在主线程接受&响应事件(实现UI操作)
- 对于一般的需求场景,需要在子线程中实现耗时操作,然后回到主线程实现UI操作
-
冲突的解决方案
所以为了解决线程冲突,实现真正的异步操作,我们对RxJava进行线程控制
-
实现方式
采用RxJava内置的线程调度器(Scheduler),即通过功能性的操作符subscribeon()&observeon()实现
-
subscribeOn()&observeOn()简介
作用:线程控制,指定观察者或者被观察者的工作线程类型
类型 含义 应用场景 Schedulers.immediate() 当前线程: =不指定线程 默认情况 AndroidSchedulers.mainThread() Android主线程 操作UI Schedulers.newThread() 常规新线程 耗时操作 Schedulers.io() io操作线程 网络请求,读写文件等io秘籍型操作 Schedulers.computation() CPU计算操作线程 大量计算操作 RxJava内部使用线程池来维护这些线程,所以线程的调度效率非常高.
-
具体使用
具体是在通过订阅(subscribe)连接观察者和被观察者中实现
<-- 使用说明 --> // Observable.subscribeOn(Schedulers.Thread):指定被观察者 发送事件的线程(传入RxJava内置的线程类型) // Observable.observeOn(Schedulers.Thread):指定观察者 接收 & 响应事件的线程(传入RxJava内置的线程类型) <-- 实例使用 --> // 步骤3:通过订阅(subscribe)连接观察者和被观察者 observable.subscribeOn(Schedulers.newThread()) // 1. 指定被观察者 生产事件的线程 .observeOn(AndroidSchedulers.mainThread()) // 2. 指定观察者 接收 & 响应事件的线程 .subscribe(observer); // 3. 最后再通过订阅(subscribe)连接观察者和被观察者
注意
-
若observable.subscribeOn()多次指定被观察者生产事件的线程,则只有第一次指定有效,其余的指定线程无效
-
若Observable.observeOn()多次指定观察者接受&响应事件的线程,则每次指定均有效,即每指定一次观察者,就会进行一次线程的切换
// 步骤3:通过订阅(subscribe)连接观察者和被观察者 observable.subscribeOn(Schedulers.newThread()) .observeOn(AndroidSchedulers.mainThread()) // 第一次指定观察者线程 = 主线程 .doOnNext(new Consumer<Integer>() { // 生产事件 @Override public void accept(Integer integer) throws Exception { Log.d(TAG, "第一次观察者Observer的工作线程是: " + Thread.currentThread().getName()); } }) .observeOn(Schedulers.newThread()) // 第二次指定观察者线程 = 新的工作线程 .subscribe(observer); // 生产事件 // 注: // 1. 整体方法调用顺序:观察者.onSubscribe()> 被观察者.subscribe()> 观察者.doOnNext()>观察者.onNext()>观察者.onComplete() // 2. 观察者.onSubscribe()固定在主线程进行
-
-
功能性的操作符
-
作用: 辅助被观察者(observable)在发送事件时实现一些功能性性需求 如错误处理,线程调度
-
类型:
类型 作用 连接观察者和被观察者 (订阅者)subscribe 线程调度 subscribeOn observeon 延迟操作 delay 在事件的生命周期中操作 do()操作符 错误处理 onErrorReturn onErrorResumeNext onExceptResumenext retry retryUntil retyWhen 重复发送 repeat repeatWhen -
连接被观察者和观察者 形成订阅关系
-
subscribe()
observable.subscribe(observer); // 前者 = 被观察者(observable);后者 = 观察者(observer 或 subscriber) <-- 1. 分步骤的完整调用 --> // 步骤1: 创建被观察者 Observable 对象 Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onComplete(); } }); // 步骤2:创建观察者 Observer 并 定义响应事件行为 Observer<Integer> observer = new Observer<Integer>() { // 通过复写对应方法来 响应 被观察者 @Override public void onSubscribe(Disposable d) { Log.d(TAG, "开始采用subscribe连接"); } // 默认最先调用复写的 onSubscribe() @Override public void onNext(Integer value) { Log.d(TAG, "对Next事件"+ value +"作出响应" ); } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } }; // 步骤3:通过订阅(subscribe)连接观察者和被观察者 observable.subscribe(observer); <-- 2. 基于事件流的链式调用 --> Observable.create(new ObservableOnSubscribe<Integer>() { // 1. 创建被观察者 & 生产事件 @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onComplete(); } }).subscribe(new Observer<Integer>() { // 2. 通过通过订阅(subscribe)连接观察者和被观察者 // 3. 创建观察者 & 定义响应事件的行为 @Override public void onSubscribe(Disposable d) { Log.d(TAG, "开始采用subscribe连接"); } // 默认最先调用复写的 onSubscribe() @Override public void onNext(Integer value) { Log.d(TAG, "对Next事件"+ value +"作出响应" ); } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } }); } } <-- Observable.subscribe(Subscriber) 的内部实现 --> public Subscription subscribe(Subscriber subscriber) { subscriber.onStart(); // 在观察者 subscriber抽象类复写的方法 onSubscribe.call(subscriber),用于初始化工作 // 通过该调用,从而回调观察者中的对应方法从而响应被观察者生产的事件 // 从而实现被观察者调用了观察者的回调方法 & 由被观察者向观察者的事件传递,即观察者模式 // 同时也看出:Observable只是生产事件,真正的发送事件是在它被订阅的时候,即当 subscribe() 方法执行时 }
-
线程调度 :参考下文
-
延迟操作 delay()
// 1. 指定延迟时间 // 参数1 = 时间;参数2 = 时间单位 delay(long delay,TimeUnit unit) // 2. 指定延迟时间 & 调度器 // 参数1 = 时间;参数2 = 时间单位;参数3 = 线程调度器 delay(long delay,TimeUnit unit,mScheduler scheduler) // 3. 指定延迟时间 & 错误延迟 // 错误延迟,即:若存在Error事件,则如常执行,执行后再抛出错误异常 // 参数1 = 时间;参数2 = 时间单位;参数3 = 错误延迟参数 delay(long delay,TimeUnit unit,boolean delayError) // 4. 指定延迟时间 & 调度器 & 错误延迟 // 参数1 = 时间;参数2 = 时间单位;参数3 = 线程调度器;参数4 = 错误延迟参数 delay(long delay,TimeUnit unit,mScheduler scheduler,boolean delayError): 指定延迟多长时间并添加调度器,错误通知可以设置是否延迟
-
在事件的生命周期中操作 do()
do()操作符有很多个.
当observable没发送一次数据事件就会调用一次 doOnEach 包含onNext,onError和onComplete Next事件 doOnNext(执行next事件之前调用) doAfterNext(执行next事件只后调用) 发送事件完毕后调用 doOnError(发送错误时) doOnComplete(发送事件完毕之后) doOnTerminate(无论正常发送完毕之后/异常终止) doOnFinally(最后执行) 订阅相关 doOnSubscribe(观察者订阅时调用) doOnUnsubscribe(观察者取消订阅时调用) -
错误处理
-
onErrorReturn() 遇到错误时,发送一个特殊事件&正常终止
-
onErrorResumeNext() 遇到错误时,发送一个新的observable
- onErrorResumeNext拦截错误=throwable 若需要拦截Exception请用onExceptionResumenext();
- 若用onErrorResumeNext拦截的错误=Exception,则会将错误传递给观察者的onError方法
-
onExceptionResumeNext(); 遇到错误,发送一个新的observable
- onExceptionResumeNext拦截的错误=Exception,若需要拦截Throwable请用onErrorResumeNext
- 若用onExceptionResumeNext拦截的错误=Throwable,则会将错误传递给观察者的onError方法
-
retry 重试:
-
接受到onError()时,重新订阅&发送
-
Throwable和Exception都可以拦截
<-- 1. retry() --> // 作用:出现错误时,让被观察者重新发送数据 // 注:若一直错误,则一直重新发送 <-- 2. retry(long time) --> // 作用:出现错误时,让被观察者重新发送数据(具备重试次数限制 // 参数 = 重试次数 <-- 3. retry(Predicate predicate) --> // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送& 持续遇到错误,则持续重试) // 参数 = 判断逻辑 <-- 4. retry(new BiPredicate<Integer, Throwable>) --> // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送 & 持续遇到错误,则持续重试 // 参数 = 判断逻辑(传入当前重试次数 & 异常错误信息) <-- 5. retry(long time,Predicate predicate) --> // 作用:出现错误后,判断是否需要重新发送数据(具备重试次数限制 // 参数 = 设置重试次数 & 判断逻辑
-
-
retryUntil 出现错误后,判断是否需要重新发送数据
具体使用类似retry,唯一区别返回true时,则不重新发送数据事件,
-
retryWhen 遇到错误将发生的错误传递给一个新的观察者(observable),并决定是否需要重新订阅原始被观察者(observer)&发送事件
-
-
重复发送
- repeat 重复不断地发送被观察者事件 无条件 具备重载方法,可设置重复创建次数
- repeatWhen 有条件,重复发送被观察者事件
- 若新被观察者observable返回一个complete/error事件,则不重新订阅&发送原来的observable
- 若新被观察者observable返回其余事件时,则重新订阅&发送原来的observable
总结
-
过滤操作符
-
作用: 过滤/筛选被观察者发送的事件&观察者接收的事件
-
类型
根据指定条件过滤事件 filter ofType ship skiplast disinct disinctUntilChanged 根据指定事件数量过滤事件 take takeLast 根据指定时间过滤事件 throttleFirst throttlelast Sample throttleWithTimeOut debounce 根据指定事件位置过滤事件 firstElement lastElement elementAt elementAtError -
根据指定条件过滤事件
需求: 通过指定的过滤条件,当且仅当事件满足条件,就将该事件过滤(不发送)
-
filter 过滤特定条件的事件
Observable.create((ObservableOnSubscribe<Integer>) emitter -> { emitter.onNext(1); emitter.onNext(10); emitter.onNext(100); emitter.onNext(1000); emitter.onNext(10000); }).filter((AppendOnlyLinkedArrayList.NonThrowingPredicate<Integer>) integer -> integer > 3) .subscribe(integer -> Log.d("admin", "过滤后得到的事件是:" + integer));
-
ofType 过滤特定数据类型数据
Observable.just("12",15,'a',189.02,15.01,"dad").ofType(Double.class).subscribe(aDouble -> Log.d("admin","获取到的整型事件元素是: "+ aDouble));
-
skip/skipLast 跳过某个事件
// 使用1:根据顺序跳过数据项 Observable.just(1, 2, 3, 4, 5) .skip(1) // 跳过正序的前1项 .skipLast(2) // 跳过正序的后2项 .subscribe(new Consumer<Integer>() { @Override public void accept( Integer integer) throws Exception { Log.d(TAG,"获取到的整型事件元素是: "+ integer); } }); // 使用2:根据时间跳过数据项 // 发送事件特点:发送数据0-5,每隔1s发送一次,每次递增1;第1次发送延迟0s Observable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS) .skip(1, TimeUnit.SECONDS) // 跳过第1s发送的数据 .skipLast(1, TimeUnit.SECONDS) // 跳过最后1s发送的数据 .subscribe(new Consumer<Long>() { @Override public void accept( Long along ) throws Exception { Log.d(TAG,"获取到的整型事件元素是: "+ along); } });
-
distinct/distinctUntilChanged 过滤事件序列中重复的事件/连续的事件
// 使用1:过滤事件序列中重复的事件 Observable.just(1, 2, 3, 1 , 2 ) .distinct() .subscribe(new Consumer<Integer>() { @Override public void accept( Integer integer) throws Exception { Log.d(TAG,"不重复的整型事件元素是: "+ integer); } }); // 使用2:过滤事件序列中 连续重复的事件 // 下面序列中,连续重复的事件 = 3、4 Observable.just(1,2,3,1,2,3,3,4,4 ) .distinctUntilChanged() .subscribe(new Consumer<Integer>() { @Override public void accept( Integer integer) throws Exception { Log.d(TAG,"不连续重复的整型事件元素是: "+ integer); } });
-
-
根据指定事件数量过滤事件
通过设置指定的事件数量,仅发送特定数量的事件
- take 指定观察者最多能接收到的事件数量
- takeLast 指定观察者只能接受到被观察者发送的最后几个事件
-
根据指定时间过滤事件
通过设置指定时间,仅发送在该时间内的事件
- throttleFirst/ throttleLast 在某段时间内,只能发送该段时间内第一次事件/最后一次事件 如1段时间内连续点击按钮,但只执行第一次的点击操作
- Smple 在某段时间内,只发送该段时间内最新(最后)1次事件 类似于throeeleLast操作符
- throttleWithTimeout / debounce 发送数据事件时,若2次发送事件的间隔<指定时间,就会丢弃前一次数据,直到指定时间内都没有新数据发射时才会发送最后一次的数据
-
根据指定事件位置过滤事件
通过设置指定位置,过滤在该位置的事件
- firstElement/ lastElement 仅选取第一个元素/最后一个元素(无参数)
- elementAt 指定接收某个元素(通过索引值确定) 允许越界,
- elementAtOrError 当出现越界情况时,即抛出异常.
功能防抖
-
功能防抖, 背景: 用户只需要使用功能1次.
-
冲突: 但是由于外部原因,多次触发了这个功能,导致出现冗余功能操作,
-
解决方案: 通过根据指定时间过滤事件的过滤操作符实现,防止功能的抖动
//使用rxbinding配合rxjava 实现2秒内点击事件只会记录第一次点击 RxView.clicks(btnSub).throttleFirst(2, TimeUnit.SECONDS).subscribe(o -> Log.e("admin", o.toString()) );
联想搜索功能
-
背景: 即当用户输入1个字符,显示当前输入框字符相关的搜索结果
-
冲突: 在用户搜索需求明确下,可能会发送一些不必要的网络请求, 如想搜索abc 其时则会发送a ab abc 三个请求
-
解决方案: 通过指定时间过滤事件的过滤操作符 debounce实现,
/* * 说明 * 1. 此处采用了RxBinding:RxTextView.textChanges(name) = 对对控件数据变更进行监听(功能类似TextWatcher),需要引入依赖:compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0' * 2. 传入EditText控件,输入字符时都会发送数据事件(此处不会马上发送,因为使用了debounce()) * 3. 采用skip(1)原因:跳过 第1次请求 = 初始输入框的空字符状态 **/ RxTextView.textChanges(edName).debounce(1, TimeUnit.SECONDS) .skip(1).observeOn(AndroidSchedulers.mainThread()) .subscribe(charSequence -> Log.e("admin", "发送给服务器的字符串为:" + charSequence)); //如果skip(1)去掉log如下: 12-19 04:34:27.492 6580-6580/com.yishion.demo_count E/admin: 发送给服务器的字符串为: 12-19 04:34:21.657 6580-6580/com.yishion.demo_count E/admin: 发送给服务器的字符串为:11111
条件/布尔操作符
-
all 用来判断发送的每项数据是否都满足,设置函数条件(满足返回True)
Observable.just(1,2,3,4,5,6) .all(new Predicate<Integer>(){ @Override public boolean test( Integer integer) throws Exception { return (integer<=10); // 该函数用于判断Observable发送的10个数据是否都满足integer<=10 } }).subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean aBoolean) throws Exception { Log.d(TAG,"result is "+ aBoolean); // 输出返回结果 } });
-
takeWhile 判断发送的每项数据都是否满足,设置函数条件(若发送的数据满足条件,则发送该项数据)
// 1. 每1s发送1个数据 = 从0开始,递增1,即0、1、2、3 Observable.interval(1, TimeUnit.SECONDS) // 2. 通过takeWhile传入一个判断条件 .takeWhile(new Predicate<Long>(){ @Override public boolean test( Long integer) throws Exception { return (integer<3); // 当发送的数据满足<3时,才发送Observable的数据 } }).subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Long value) { Log.d(TAG,"发送了事件 "+ value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
-
shipWhile 判断发送的每项数据是否满足,设置函数条件 (直到改判断条件=false时,才开始发送observable的数据)
// 1. 每隔1s发送1个数据 = 从0开始,每次递增1 Observable.interval(1, TimeUnit.SECONDS) // 2. 通过skipWhile()设置判断条件 .skipWhile(new Predicate<Long>(){ @Override public boolean test( Long aLong) throws Exception { return (aLong<5); // 直到判断条件不成立 = false = 发射的数据≥5,才开始发送数据 } }).subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Long value) { Log.d(TAG,"发送了事件 "+ value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
-
takeUntil 执行到某个条件时,停止发送事件
// 1. 每1s发送1个数据 = 从0开始,递增1,即0、1、2、3 Observable.interval(1, TimeUnit.SECONDS) // 2. 通过takeUntil的Predicate传入判断条件 .takeUntil(new Predicate<Long>(){ @Override public boolean test( Long integer) throws Exception { return (integer>3); // 返回true时,就停止发送事件 // 当发送的数据满足>3时,就停止发送Observable的数据 } }).subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(Long value) { Log.d(TAG,"发送了事件 "+ value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); //该判断条件也可以是observable 即等到takeUntil传入observable开始发送数据,第一个observable的数据停止发送数据
-
skipUntil 等到skipUntil传入的observable开始发送数据,第一个observable的数据才开始发送数据
// (原始)第1个Observable:每隔1s发送1个数据 = 从0开始,每次递增1 Observable.interval(1, TimeUnit.SECONDS) // 第2个Observable:延迟5s后开始发送1个Long型数据 .skipUntil(Observable.timer(5, TimeUnit.SECONDS)) .subscribe(new Observer<Long>() { @Override public void onSubscribe(Disposable d) { Log.d(TAG, "开始采用subscribe连接"); } @Override public void onNext(Long value) { Log.d(TAG, "接收到了事件"+ value ); } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } });
-
sequenceEqual 判断二个observable需要发送的数据是否相同 返回true和fasle
Observable.sequenceEqual( Observable.just(4,5,6), Observable.just(4,5,6) ) .subscribe(new Consumer<Boolean>() { @Override public void accept( Boolean aBoolean) throws Exception { Log.d(TAG,"2个Observable是否相同:"+ aBoolean); // 输出返回结果 } });
-
contains 判断发送的数据汇总是否包含指定数据
Observable.just(1,2,3,4,5,6) .contains(4) .subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean aBoolean) throws Exception { Log.d(TAG,"result is "+ aBoolean); // 输出返回结果 } });
-
isEmpty 判断发送的2数据是否为空
Observable.just(1,2,3,4,5,6) .isEmpty() // 判断发送的数据中是否为空 }).subscribe(new Action1<Boolean>() { @Override public void call(Boolean aBoolean) { Log.d(TAG,"result is "+ aBoolean); // 输出返回结果 } });
-
amb 当需要发送福讴歌observable时,只发送先发送数据的observable的数据,而其余observable则被丢弃
// 设置2个需要发送的Observable & 放入到集合中 List<ObservableSource<Integer>> list= new ArrayList <>(); // 第1个Observable延迟1秒发射数据 list.add( Observable.just(1,2,3).delay(1,TimeUnit.SECONDS)); // 第2个Observable正常发送数据 list.add( Observable.just(4,5,6)); // 一共需要发送2个Observable的数据 // 但由于使用了amba(),所以仅发送先发送数据的Observable // 即第二个(因为第1个延时了) Observable.amb(list).subscribe(new Consumer<Integer>() { @Override public void accept(Integer integer) throws Exception { Log.e(TAG, "接收到了事件 "+integer); } });
-
defaultEmpty 在不发送任何有效时间,仅发送了complete时间的前提下,发送一个默认值
Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> e) throws Exception { // 不发送任何有效事件 // e.onNext(1); // e.onNext(2); // 仅发送Complete事件 e.onComplete(); } }).defaultIfEmpty(10) // 若仅发送了Complete事件,默认发送 值 = 10 .subscribe(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { Log.d(TAG, "开始采用subscribe连接"); } @Override public void onNext(Integer value) { Log.d(TAG, "接收到了事件"+ value ); } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } });