定义
RxJava 是一个 基于事件流、实现异步操作的库
优点
逻辑简洁、实现优雅、使用简单
随着程序逻辑的复杂性提高,它依然能够保持简洁 & 优雅
原理
1)RxJava 原理 基于 一种扩展的 观察者模式
4个角色,相互关系:
角色 | 作用 | 类比 |
---|---|---|
被观察者(Observable) | 产生事件 | 顾客 |
观察者(Observer) | 接收事件,并给出响应动作 | 厨房 |
订阅(Subscribe) | 连接 被观察者 & 观察者 | 服务员 |
事件(Event) | 被观察者 & 观察者 沟通的载体 | 菜式 |
被观察者 (Observable) 通过 订阅(Subscribe) 按顺序发送事件 给观察者 (Observer),
观察者(Observer) 按顺序接收事件 & 作出对应的响应动作。
RxJava1.0 与 2.0对比
区别 | Observable | Flowable |
---|---|---|
版本实现 | RxJava 1.0就存在 | RxJava2.0才有 |
角色订阅关系 | 对应观察者 Observer | 对应观察者 Subscriber |
功能 | Observable在 1.0 支持背压 (效果不好) 1、手动减少Observable发送的事件 2、延迟的方式降低 Observable 发射速度 Observable 在 2.0开始,不支持背压 | Flowable 所有操作符强制支持背压 |
应用场景 | 小数据流传输 默认缓存大小 = 16 | 大数据流传输 默认缓存大小 = 128 |
观察者创建方式
创建方式 | 实现 | 说明 |
---|---|---|
创建 Observer 对象 | new Observer<T>() | 观察者接收事件前,最先调用 onSubscribe() |
创建 Subscriber 对象 | new Subscriber<T>() | Subscriber类 是 RxJava 内置实现了 Observer 的抽象类 比 Observer 增加了 onStart() unsubscribe()两个方法 onStart():响应事件前调用 unsubscribe():用于取消订阅。 在该方法被调用后,观察者将不再接收 & 响应事件 调用该方法前,先使用 isUnsubscribed() 判断状态 确定被观察者 Observable 是否还持有观察者 Subscriber 的引用, 如果引用不能及时释放,就会出现内存泄露 |
Action、BiConsumer、BiFunction Cancellable、Consumer、Function Function3… | Consumer 每次接收到事件都会调用 Consumer # accept() |
订阅:连接观察者、被观察者
observable.subscribe(observer) 或者 observable.subscribe(subscriber)
订阅方法 | 说明 | 说明2 |
---|---|---|
Observable # subscribe() | 观察者不对任何事件做出响应 | 被观察者可以发送 |
Observable # subscribe(Consumer<? super T> onNext) | 观察者只对 Next事件 作出响应 | 参数表示观察者响应的事件类型 |
subscribe(Observer<? super T> observer) | 观察者对任何事件都作出响应 |
调用顺序
观察者.onSubscribe() > 被观察者.subscribe() > 观察者.onNext() > 观察者.onComplete()
取消订阅
Disposable.dispose() 切断观察者 与 被观察者 之间的连接
观察者订阅回调函数 onSubscribe(Disposable d) 中,获取 Disposable 引用
在观察者 onNext() 中,按需要执行 Disposable # dispose()
创建被观察者Observable
创建方式 | 说明 |
---|---|
Observable.create(ObservableOnSubscribe) | 在 subscribe(ObservableEmitter emitter) 定义发射事件 ObservableEmitter 事件发射器 if (!observer.isUnsubscribed()) {// 没有观察者时,Observable停止发射 emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); } emitter.onComplete(); |
Observable.just(1, 2, 3,4) | 创建 被观察者对象(Observable) 只能 发送10个以下事件 |
Observable.fromArray(items) | 参数为 数组 如果传一个 list 集合进去,会把 list 当做一个数据元素发送 场景:10 个以上数组形式事件 或者 数组遍历 |
Observable.fromIterable(list) | 发送 传入的集合 List 数据 场景: 发送10个以上事件(集合形式) 或者 集合元素遍历 |
Observable.empty() | 仅发送 Complete 事件,观察者接收后会直接调用 onCompleted() |
Observable.error(new RuntimeException()) | 仅发送 Error事件,可自定义异常,观察者接收后会直接调用onError() |
Observable.never() | 不发送任何事件, 观察者接收后什么都不调用 |
Observable.defer() | 延迟到 有观察者(Observer) 订阅时,才动态创建 Observable & 发送事件 场景:动态创建 Observable & 获取最新的 Observable 对象数据 |
Observable.timer(2, TimeUnit.SECONDS) | 延迟指定时间后,调用一次 onNext(0) 延迟指定时间,发送一个0 (Long类型),一般用于检测 timer()操作符默认运行在一个新线程上 自定义线程调度器(第3个参数):timer(long, TimeUnit, Scheduler) |
Observable.interval(3 , 1 , TimeUnit.SECONDS) 参数1 = 第1次延迟时间; 参数2 = 间隔时间数字; 参数3 = 时间单位 | 每隔指定时间 就发送 事件 发送的事件序列 = 从0开始、无限递增 1 的整数序列 interval() 默认在 computation 调度器上执行 可指定线程调度器(第3个参数):interval(long, TimeUnit, Scheduler) |
Observable.intervalRange(3 ,10 , 2, 1, TimeUnit.SECONDS) 参数1 = 事件序列起始点; 参数2 = 事件数量; 参数3 = 第1次事件延迟发送时间; 参数4 = 间隔时间数字; 参数5 = 时间单位 | 每隔指定时间 就发送从 0开始、无限递增1 的整数序列 可指定发送的数据的数量 |
Observable.range(3 ,10) 参数1 = 事件序列起始点; 参数2 = 事件数量; 若设置为负数,则会抛出异常 | 无延迟,连续发送 1 个每次递增 1 的整数事件序列,可指定范围 |
Observable.rangeLong(…) | 类似 range(),区别在于 该操作符支持数据类型 = Long |
RxJava变换操作符
操作符 | 说明 | 使用 |
---|---|---|
map() | 将 Observable 发送的事件,转换为任意的类型事件 场景:数据类型转换 | observable.map(new Function<Integer, String>()) 使用 Function 函数对事件进行统一变换 观察者接收到的是 变换后的事件 |
flatMap() | 将 Observable 发送的事件进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送 场景:无序的将 Observable 的整个事件序列进行变换 步骤: 1.为每个事件都创建一个 Observable 对象 2.每个 原始事件 转换成 新事件,放入到对应 Observable 对象 3.将新建的每个 Observable 都合并到一个新建的、总的 Observable 对象 4.新的、总的 Observable 对象,将 新合并的事件序列,发送给观察者 | observable.flatMap(new Function<Integer, ObservableSource<String>>()) Integer 每个原始事件转成 String 类型,放入 Observable 多个Observable 合并成一个总的Observable对象,发送给观察者 flatMap 事件转换是无序的 |
concatMap() | 作用类似flatMap()操作符 与flatMap()区别:新的 Observable 事件序列 的顺序 == 原始 Observable 事件序列的顺序 场景:有序的 将 Observable 发送的整个事件序列进行转换 | .concatMap(new Function<Integer, ObservableSource<String>>()) |
buffer(3, 1) 设置缓存区大小 & 步长 参数一:缓存区大小 = 每次从Observable 获取的事件数量 参数二:步长 = 每次向右偏移步长 | 从 Obervable 事件序列中, 获取一定数量的事件 放到缓存,发送整个缓存的事件 然后,向右偏移一定步长,继续获取缓存并发送 | Observable.just(1, 2, 3, 4, 5) .buffer(3, 1) .subscribe(…) 每次从 Observable 获取 3个 事件 每次发射缓存事件后,向右偏移的 1 步 第一次获取 1、2、3,第二次获取2、3、4,… |
RxJava组合、合并操作符
操作符 | 说明 | 使用 |
---|---|---|
concat() | 组合 <= 4 个 Observable,按发送顺序,串行执行 | |
concatArray() | 组合 > 4 个 Observable,按发送顺序,串行执行 | |
merge() | 组合 <= 4 个 Observable,按时间线,并行执行 | Observable.merge( // 从0开始、发送3个数据、间隔时间 1s,每次递增1 Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS), // 从2开始、发送3个数据、间隔时间 1s,每次递增1 Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS) ) .subscribe(…) 结果:两个被观察者发送事件并行执行 输出结果 = 0,2 -> 1,3 -> 2,4 |
mergeArray() | 组合 > 4 个 Observable,按时间线,并行执行 | |
concatDelayError()、mergeDelayError() | 组合多个 Observable 时, 一个 Observable发出 Error事件, onError() 事件推迟到其他 Observable 发送结束后才触发 | Observable.concatArrayDelayError( observable1, observable2, …).subscribe(…) |
zip() | 按个数合并,即 1对1 合并 合并后新 Observable 的事件数量 = 多个 Observable 数量最少 的数量 | observable1 [1,2,3] observable2 [A,B,C,D] 合并后新Observable [1A, 2B, 3C] 按数量一对一合并 1、observable2 事件D 没有合并,但是会发送,订阅在新Observable上的观察者不会接收到事件D 2、若observable1 & observable2 最后都发送 onComplete()事件,则 事件D 不会发送 |
combineLatest() | 两个 Observable 中的任何一个发送了数据后, 先发送了数据的 Observable 的最新一个数据 与 另一个 Observable 发送的每个数据结合, 最终基于该函数的结果发送数据 | 合并规则,见下图 |
combineLatestDelayError() | 一个 Observable 的 onError() 事件,延迟到另一个 Observable 的事件发送完之后再发送 | |
reduce() | 把 Observable 发送的事件聚合成1个事件 & 发送 第1次取前2个数据聚合,然后聚合结果与下1个数据继续进行聚合 | Observable.just(1,2,3,4) .reduce(new BiFunction<Integer, Integer, Integer>()) 假设 reduce() 函数 return event1 * event2; 结果:24 |
collect() | 将 Observable 发送的事件收集到一个数据结构里 | Observable.just(1, 2, 3 ,4, 5, 6) .collect(new Callable<ArrayList>() , new BiConsumer<ArrayList, Integer>()) .subscribe(…) 结果:发送一个List,List 数据:[1,2,3,4,5,6] |
startWith() startWithArray() | 在一个 Observable 发送事件前,追加 发送一些数据 / 一个新的被观察者 | Observable.just(4, 5, 6) .startWith(0) .startWithArray(1, 2, 3) 追加数据顺序 = 后调用先追加 结果:[1, 2, 3, 0, 4, 5, 6] |
count() | 统计 Observable 发送事件的数量 | Observable.just(1, 2, 3, 4) .count() |
combineLatest 组合规则:
RxJava功能性操作符
操作符 | 说明 |
---|---|
subscribe() | 通过订阅(subscribe)连接观察者和被观察者 observable.subscribe(observer); |
subscribeOn() | 设置 Observable 执行的线程 |
observeOn() | 设置 Observer 执行的线程 |
delay() | 延时操作 Observable.just(1, 2, 3) .delay(3, TimeUnit.SECONDS) 延迟3s再发送 |
doXXX() | 在事件的生命周期中操作 .doOnEach():Observable 每发送1次事件,就调用1次 doOnNext():执行Next事件前调用 doAfterNext()执行Next事件后调用 doOnComplete():Observable正常发送事件完毕后调用 doOnError():Observable发送错误事件时调用 doOnSubscribe():观察者订阅时调用 doAfterTerminate():Observable 发送事件完毕后调用,无论正常发送完毕 / 异常终止 doFinally():最后执行 |
onErrorReturn() | 发送事件时,错误处理机制,可捕获在它之前发生的异常 |
onErrorResumeNext() | 拦截 Throwable 错误 遇到错误时,发送1个新的Observable |
onExceptionResumeNext() | 拦截 Exception 错误 遇到错误时,发送1个新的Observable |
retry() | 出现错误时,让 Observable 重新发送数据 若一直错误,则一直重新发送 |
retry(long times) | 出现错误时,让 Observable 重新发送数据,参数 = 重试次数 |
retry(Predicate predicate) | 出现错误后,判断是否需要重新发送数据(若需要重新发送& 持续遇到错误,则持续重试) 参数 = 判断逻辑 返回 true = 重新发送请求 返回 false = 不重新发送数据 & 调用观察者的 onError 结束 |
retry(new BiPredicate<Integer, Throwable>) | 出现错误后,判断是否需要重新发送数据(若需要重新发送& 持续遇到错误,则持续重试) 参数 = 判断逻辑 返回 true = 重新发送请求 返回 false = 不重新发送数据 & 调用观察者的 onError 结束 retry函数中,可获取重试的次数 |
retry(long time,Predicate predicate) | 出现错误后,判断是否需要重新发送数据(具备重试次数限制) 参数 = 设置重试次数 & 判断逻辑 |
retryUntil() | 遇到错误时,若需要重新发送 & 持续遇到错误,则持续重试 作用类似 retry(Predicate predicate) 唯一区别:返回 true 则 不重新发送数据事件 |
retryWhen() | 遇到错误时,将发生的错误传给一个新的 Observable 并决定是否需要重新订阅原始 Observable & 发送事件 1.若新的 Observable发送的事件 = Error事件,原始 Observable 不重新发送事件 发送 Error 事件后结束 2.新的 Observable 发送的事件 = Next事件 ,原始 Observable 重新发送事件 |
repeat() | 接收到.onCompleted()事件后,触发重新订阅 & 发送 默认运行在一个新的线程上 不传入参数 = 无限重复发送 |
repeatWhen() | 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据 传递给1个新 Observable,以此决定是否重新订阅 & 发送原来的 Observable 新 Observable 返回1个 Complete / Error 事件,则不重新订阅 新 Observable 返回其余事件时,则重新订阅 & 发送原来的 Observable |
线程调度
类型 | 含义 | 场景 |
---|---|---|
Schedulers.immediate() | 当前线程 = 不指定线程 | 默认 |
AndroidSchedulers.mainThread() | Android主线程 | 操作UI |
Schedulers.newThread() | 常规新线程 | 耗时等操作 |
Schedulers.io() | io操作线程 | 网络请求、读写文件等io密集型操作 |
Schedulers.computation() | CPU计算操作线程 | 大量计算操作 |
RxJava内部使用【线程池】来维护这些线程,所以线程的调度效率非常高
RxJava过滤操作符
操作符 | 说明 |
---|---|
filter() | 过滤 特定条件的事件 返回 true,则继续发送 返回 false,则不发送(即过滤) |
ofType() | 筛选出 特定数据类型的数据 .ofType(Integer.class) // 筛选出 整型数据,其他类型的数据会被过滤掉 |
skip()/skipLast() | 跳过某个事件 Observable.just(1, 2, 3, 4, 5) .skip(1) // 跳过正序的前1项,过滤掉了1 .skipLast(2) // 跳过正序的后2项,过滤掉了4,5 场景:跳过 一开始 EditText 无任何输入时的空值 RxTextView.textChanges(name).skip(1); |
distinct() | 过滤 重复的事件 Observable.just(1, 2, 3, 1 , 2 ) .distinct() //过滤掉重复的 1,2 结果:1,2,3 |
distinctUntilChanged() | 过滤事件序列 连续重复的事件 Observable.just(1,2,3,1,2,3,3,4,4 ) .distinctUntilChanged() //过滤连续重复的3,4;非连续的不会过滤 结果:1,2,3,1,2,3,4 |
take() | 指定观察者最多能接收到的事件数量 observable.take(2) 指定观察者只能接收2个事件 |
takeLast() | 指定观察者只能接收到被观察者发送的最后几个事件 observable.takeLast(3) // 指定观察者只能接受 Observable 发送的最后3个事件 |
throttleFirst() / throttleLast() | 在某段时间内,只发送该段时间内第1次事件 / 最后1次事件 observable.throttleFirst(1, TimeUnit.SECONDS) //仅发送每1秒中,的第一个事件 observable.throttleLast(1, TimeUnit.SECONDS) // 仅发送每1秒中,的最后一个事件 运用:防止重复点击 |
sample() | 与 throttleLast() 操作符类似 在某段时间内,只发送该段时间内最新(最后)1次事件 |
throttleWithTimeout() / debounce() | 发送数据事件时,若2次发送事件的间隔<指定时间,就会丢弃前一次的数据 observable.throttleWithTimeout(1, TimeUnit.SECONDS) // 丢弃间隔小于指定时间1s 的前一次数据 运用:输入框输入操作控制每指定时间触发一次回调 |
firstElement() / lastElement() | 仅选取第1个元素 / 最后一个元素 |
elementAt( index ) | 指定接收某个元素(通过 索引值 确定),位置索引从0开始 .elementAt(6 ,10) // 默认值是10,位置6越界,则发送默认值10 |
elementAtOrError( index ) | 指定接收某个元素(通过 索引值 确定),位置索引从0开始 越界时发送 NoSuchElementException 错误 |
RxJava背压
一种 控制事件流速 的策略,对超出缓存区大小的事件进行丢弃、保留、报错的措施。
在【异步订阅关系】中,控制事件发送 & 接收的速度
场景:比如,网络请求。
操作符 | 说明 | 特点 |
---|---|---|
同步订阅 | Observer & Observable 工作【在同一线程】 | Observable 每发送1个事件,必须等 Observer 接收& 处理后 才能继续发送下一事件 |
异步订阅 | Observer & Observable 工作【在不同线程】 | Observable 不断发送,直到发送事件完毕 不需要 等待 Observer 接收& 处理 事件先发送到缓存区,Observer 从缓存区取出事件处理 |
问题 | Observable 发送事件速度 与 Observer 接收事件速度 不匹配 | Observable 发送事件速度太快,Observer 来不及接收所有事件, 导致观察者无法及时响应 / 处理事件, 最终导致 缓存区溢出、事件丢失 & OOM |
解决 | 采用背压策略 | Flowable:RxJava 2.0 Observable 的一种新实现, 是背压策略实现的承载者 |
Flowable | 1、对应的 观察者 为 Subscriber 2、所有的操作符 强制支持背压 3、缓存区存放策略:类似队列,FIFO,先进先出 4、默认的缓存区(队列)大小 = 128 | Flowable.create( // 需要传入背压策略 new FlowableOnSubscribe() , BackpressureStrategy.ERROR ).subscribe(new Subscriber(…)); |
背压策略模式 BackpressureStrategy | 当缓存区大小存满 Observable 继续发送事件时 处理策略 | 1)BackpressureStrategy.ERROR 抛出 MissingResourceException 2)BackpressureStrategy.MISSING 友好提示:缓冲区满了 3)BackpressureStrategy.BUFFER 将缓存区大小设置成无限大 4)BackpressureStrategy.DROP 超过缓存区大小(128) 的事件丢弃 5)BackpressureStrategy.LATEST 只保存最新(最后事件),超过缓存区大小的事件丢弃 |
背压策略选择 | 1、手动创建FLowable 时,可传入参数选择背压策略 2、自动创建 FLowable 时,背压策略选择: 1) 默认 BackpressureStrategy.ERROR 模式 2) onBackpressureBuffer():缓存区设置成无限大 3) onBackpressureDrop():超过缓存区大小(128) 的事件丢弃 4) onBackpressureLatest():只保存最新(最后事件),超过缓存区大小的事件丢弃 |
背压策略—控制 Subscriber 接收事件 的速度
操作符 | 说明 | 实现 |
---|---|---|
异步订阅 | 响应式拉取: Subscriber 按需接收事件 | 1、在观察者 Subscriber # onSubscribe(Subscription s) 方法中 调用 Subscription # request ( count ) 指定 Subscriber 接收的事件数量 2、未设置 Subscription.request(long n),即说明观察者不接收事件 Flowable 能继续发送事件(存放在缓存区) 缓存区溢出时,报错 MissingResourceException 3、onSubscribe(Subscription s) 参数 Subscription Subscription.cancel():作用等同于 Disposable.dispose()切断连接 Subscription.request(long n):指定 Subscriber 接收的事件数量 |
同步订阅 | 不会出现 Flowable 发送事件速度 > Subscriber 接收事件速度 会出现Flowable 发送事件数量 > Subscriber 接收事件数量 | 1、同步订阅没有缓存区 Flowable 在发送1个事件后,必须等待 Subscriber 接收后,才能继续发下1个事件 2、如果 Subscriber 没有设置 Subscription.request(long n) Flowable 发送第一个事件,就抛出 MissingResourceException |
背压策略—控制 Flowable 发送事件 的速度
操作符 | 说明 |
---|---|
反馈控制 | Flowable 根据 Subscriber 的接收能力,控制发送事件速度 通过 Flowable 事件发射器 FlowableEmitter # requested() 方法控制流速 |
同步订阅 | FlowableEmitter.requested() 返回值 == Subscriber # Subscription.request(a) 的参数值 Flowable 通过 FlowableEmitter.requested() 返回值,知道了 Subscriber 接收事件的能力, 根据该信息控制事件发送速度,达到观察者反向控制被观察者的效果。 |
异步订阅 | 1、Flowable FlowableEmitter.requested() == Flowable 线程中 RxJava 内部调用的 request(n)的n值 (n=128、96、0) 从而每次发送128、96、或0个事件给观察者 2、由于 Flowable 与 Subscriber 处于不同线程, Flowable 无法通过 FlowableEmitter.requested() 知道观察者接收事件的能力, 只能通过 RxJava 内部固定设置,反向控制 Flowable 的发送事件速度 |
FlowableEmitter.requested() 事件发射器,可发送事件数 | 1、可叠加性 Subscriber 可连续要求接收事件,Flowable 会进行叠加、并一起发送 2、实时更新性 每次发送 Next 事件后, FlowableEmitter.requested() 返回值会实时更新 complete & error事件不算 3、异常 FlowableEmitter.requested() 返回值 = 0 时,代表观察者已经不可接收事件 此时,Flowable 继续发送事件,会抛出 MissingResourceException |
RxJava运用场景
场景 | 说明 |
---|---|
网络请求轮询 | Observable .interval(2 ,1 ,TimeUnit.SECONDS) .doOnNext(//网络请求) |
网络请求嵌套回调 | observable1.subscribeOn(Schedulers.io())// (初始被观察者)切换到IO线程进行网络请求1 .observeOn(AndroidSchedulers.mainThread()) // (新观察者)切换到主线程 处理网络请求1的结果 .doOnNext(// 第1次网络请求成功") .observeOn(Schedulers.io()) //切换到IO线程去发起请求2 .flatMap(return observable2;)// 将网络请求1转换成网络请求2,即发送网络请求2 .observeOn(AndroidSchedulers.mainThread()) //(初始观察者)切换到主线程 处理网络请求2的结果 .subscribe(…) |
从磁盘/内存缓存中 获取缓存数据 | Observable.concat(memory, disk, network) .firstElement() .subscribe(…) 按顺序串行发射 |
合并数据源 & 同时展示 | Observable .merge(network, file) .subscribe() Observable.zip(observable1, observable2, …) |
联合判断多个事件 | Observable.combineLatest() |
背压策略—控制 Subscriber 接收速度 代码实现:
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
// 一共发送4个事件
Log.d(TAG, "发送事件 1");
emitter.onNext(1);
Log.d(TAG, "发送事件 2");
emitter.onNext(2);
Log.d(TAG, "发送事件 3");
emitter.onNext(3);
Log.d(TAG, "发送事件 4");
emitter.onNext(4);
Log.d(TAG, "发送完成");
emitter.onComplete();
}
}, BackpressureStrategy.ERROR)
.subscribeOn(Schedulers.io()) // 设置被观察者在io线程中进行
.observeOn(AndroidSchedulers.mainThread()) // 设置观察者在主线程中进行
.subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
/* 对比Observer传入的Disposable参数,Subscriber此处传入的参数 = Subscription
* 相同点:Subscription参数具备Disposable参数的作用,即Disposable.dispose()切断连接, 同样的调用Subscription.cancel()切断连接
* 不同点:Subscription增加了void request(long n)
*/
/* 作用:决定观察者能够接收多少个事件
* 如设置了s.request(3),这就说明观察者能够接收3个事件(多出的事件存放在缓存区)
* 官方默认推荐使用Long.MAX_VALUE,即s.request(Long.MAX_VALUE);
*/
s.request(3);
}
...
});
背压—控制 Flowable 发送事件 的速度 代码实现
-
同步订阅 控制 Flowable
Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { // 获取 Subscriber 需要接收的事件数量 n long n = emitter.requested(); // 根据 Subscriber 可接收数量,确定发射事件数 n for (int i = 0; i < n; i++) { emitter.onNext(i);//发射事件 } } }, BackpressureStrategy.ERROR) .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { // 设置 Subscriber 每次接受 10个事件 s.request(10); } ... });
-
异步订阅 控制 Flowable
Flowable.create(new FlowableOnSubscribe<Integer>() { @Override public void subscribe(FlowableEmitter<Integer> emitter) throws Exception { /* 异步订阅时,这个值是 RxJava 内部调用 request(n)的参数值 * 该内部调用 会在一开始就调用 request(128) * 与 Subscriber 中 request()传入值 无关 */ long n = emitter.requested(); for (int i = 0; i < n; i++) { emitter.onNext(i);//发射事件 } } }, BackpressureStrategy.ERROR) .subscribeOn(Schedulers.io()) //设置 Flowable 在io线程中进行 .observeOn(AndroidSchedulers.mainThread()) //设置 Subscriber 在主线程中进行 .subscribe(new Subscriber<Integer>() { @Override public void onSubscribe(Subscription s) { /* * 该设置仅影响 Subscriber 线程中的 requested * 不会影响的 Flowable 的 FlowableEmitter.requested()的返回值 * 因为 FlowableEmitter.requested()的返回值 取决于RxJava内部调用 request(n) * 而该内部调用会在一开始就调用 request(128) */ s.request(150); } ... });
RxJava运用场景
1、网络请求轮询
1)无条件网络请求
/*
* 步骤1:采用interval()延迟发送
* 注:此处主要展示无限次轮询,若要实现有限次轮询,仅需将interval()改成 intervalRange()即可
**/
Observable.interval(2 ,1 ,TimeUnit.SECONDS)
// 参数说明:
// 参数1 = 第1次延迟时间;
// 参数2 = 间隔时间数字;
// 参数3 = 时间单位;
// 该例子发送的事件特点:延迟2s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
/*
* 步骤2:每次发送数字前发送1次网络请求(doOnNext()在执行Next事件前调用)
* 即每隔1秒产生1个数字前,就发送1次网络请求,从而实现轮询需求
*/
.doOnNext(new Consumer<Long>() {
@Override
public void accept(Long integer) throws Exception {
Log.d(TAG, "第 " + integer + " 次轮询" );
//这里实现网络请求(需要自己设置线程)
...
}
}).subscribe(new Observer<Long>() {
...
});
2)有条件网络请求
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
// 采用Observable<...>形式 对 网络请求 进行封装
Observable<Translation> observable = request.getCall();
// 发送网络请求 & 通过repeatWhen()进行轮询
observable.repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
@Override
// 在Function函数中,必须对输入的 Observable<Object>进行处理,此处使用flatMap操作符接收上游的数据
public ObservableSource<?> apply(@NonNull Observable<Object> objectObservable) throws Exception {
// 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable)
// 以此决定是否重新订阅 & 发送原来的 Observable,即轮询
// 此处有2种情况:
// 1. 若返回1个Complete() / Error()事件,则不重新订阅 & 发送原来的 Observable,即轮询结束
// 2. 若返回其余事件,则重新订阅 & 发送原来的 Observable,即继续轮询
return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Object throwable) throws Exception {
// 加入判断条件:当轮询次数 = 5次后,就停止轮询
if (i > 3) {
// 此处选择发送onError事件以结束轮询,因为可触发下游观察者的onError()方法回调
return Observable.error(new Throwable("轮询结束"));
}
// 若轮询次数<4次,则发送1Next事件以继续轮询
// 注:此处加入了delay操作符,作用 = 延迟一段时间发送(此处设置 = 2s),以实现轮询间间隔设置
return Observable.just(1).delay(2000, TimeUnit.MILLISECONDS);
}
});
}
}).subscribeOn(Schedulers.io()) // 切换到IO线程进行网络请求
.observeOn(AndroidSchedulers.mainThread()) // 切换回到主线程 处理请求结果
.subscribe(new Observer<Translation>() {
...
});
2、网络请求嵌套回调
// 创建 网络请求接口 的实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
// 采用Observable<...>形式 对 2个网络请求 进行封装
observable1 = request.getCall();
observable2 = request.getCall_2();
observable1.subscribeOn(Schedulers.io()) // (初始被观察者)切换到IO线程进行网络请求1
.observeOn(AndroidSchedulers.mainThread()) // (新观察者)切换到主线程 处理网络请求1的结果
.doOnNext(new Consumer<Translation1>() {
@Override
public void accept(Translation1 result) throws Exception {
Log.d(TAG, "第1次网络请求成功");
// 对第1次网络请求返回的结果进行操作 = 显示翻译结果
result.show();
}
})
// (新被观察者,同时也是新观察者)切换到IO线程去发起登录请求
.observeOn(Schedulers.io())
// 特别注意:因为flatMap 是对初始被观察者作变换,所以对于旧被观察者,它是新观察者,所以通过observeOn切换线程
// 但对于初始观察者,它则是新的被观察者
.flatMap(new Function<Translation1, ObservableSource<Translation2>>() { // 作变换,即作嵌套网络请求
@Override
public ObservableSource<Translation2> apply(Translation1 result) throws Exception {
// 将网络请求1转换成网络请求2,即发送网络请求2
return observable2;
}
})
.observeOn(AndroidSchedulers.mainThread()) //(初始观察者)切换到主线程 处理网络请求2的结果
.subscribe(new Consumer<Translation2>() {
@Override
public void accept(Translation2 result) throws Exception {
Log.d(TAG, "第2次网络请求成功");
result.show();
// 对第2次网络请求返回的结果进行操作 = 显示翻译结果
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
System.out.println("登录失败");
}
});
3、从磁盘/内存缓存中 获取缓存数据
// 该2变量用于模拟内存缓存 & 磁盘缓存中的数据
String memoryCache = null;
String diskCache = "从磁盘缓存中获取数据";
/*
* 设置第1个Observable:检查内存缓存是否有该数据的缓存
**/
Observable<String> memory = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
// 先判断内存缓存有无数据
if (memoryCache != null) {
// 若有该数据,则发送
emitter.onNext(memoryCache);
} else {
// 若无该数据,则直接发送结束事件
emitter.onComplete();
}
}
});
/*
* 设置第2个 Observable:检查磁盘缓存是否有该数据的缓存
**/
Observable<String> disk = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
// 先判断磁盘缓存有无数据
if (diskCache != null) {
// 若有该数据,则发送
emitter.onNext(diskCache);
} else {
// 若无该数据,则直接发送结束事件
emitter.onComplete();
}
}
});
/*
* 设置第3个 Observable:通过网络获取数据
**/
Observable<String> network = Observable.just("从网络中获取数据");
// 此处仅作网络请求的模拟
/*
* 通过 concat() 和 firstElement()操作符实现缓存功能
**/
// 1. 通过concat()合并memory、disk、network 3个被观察者的事件(即检查内存缓存、磁盘缓存 & 发送网络请求)
// 并将它们按顺序串联成队列
Observable.concat(memory, disk, network)
// 2. 通过firstElement(),从串联队列中取出并发送第1个有效事件(Next事件),
// 即依次判断检查memory、disk、network
.firstElement()
// 即本例的逻辑为:
// a. firstElement()取出第1个事件 = memory,即先判断内存缓存中有无数据缓存;
// 由于memoryCache = null,即内存缓存中无数据,所以发送结束事件(视为无效事件)
// b. firstElement()继续取出第2个事件 = disk,即判断磁盘缓存中有无数据缓存:
// 由于diskCache ≠ null,即磁盘缓存中有数据,所以发送Next事件(有效事件)
// c. 即firstElement()已发出第1个有效事件(disk事件),所以停止判断。
// 3. 观察者订阅
.subscribe(new Consumer<String>() {
@Override
public void accept( String s) throws Exception {
Log.d(TAG,"最终获取的数据来源 = "+ s);
}
});
4、合并数据源 & 同时展示
1)merge()
// 用于存放最终展示的数据
String result = "数据源来自 = " ;
/*
* 设置第1个Observable:通过网络获取数据
* 此处仅作网络请求的模拟
**/
Observable<String> network = Observable.just("网络");
/*
* 设置第2个Observable:通过本地文件获取数据
* 此处仅作本地文件请求的模拟
**/
Observable<String> file = Observable.just("本地文件");
/*
* 通过merge()合并事件 & 同时发送事件
**/
Observable.merge(network, file)
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String value) {
Log.d(TAG, "数据源有: "+ value );
result += value + "+";
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应");
}
// 接收合并事件后,统一展示
@Override
public void onComplete() {
Log.d(TAG, "获取数据完成");
Log.d(TAG, result );
}
});
2)zip()
// 步骤2:创建 网络请求接口 的实例
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
// 步骤3:采用Observable<...>形式 对 2个网络请求 进行封装
observable1 = request.getCall().subscribeOn(Schedulers.io()); // 新开线程进行网络请求1
observable2 = request.getCall_2().subscribeOn(Schedulers.io());// 新开线程进行网络请求2
// 即2个网络请求异步 & 同时发送
// 步骤4:通过使用Zip()对两个网络请求进行合并再发送
Observable.zip(observable1, observable2,
new BiFunction<Translation1, Translation2, String>() {
// 注:创建 BiFunction 对象传入的第3个参数 = 合并后数据的数据类型
@Override
public String apply(Translation1 translation1, ranslation2 translation2) throws Exception {
return translation1.show() + " & " +translation2.show();
}
}).observeOn(AndroidSchedulers.mainThread()) // 在主线程接收 & 处理数据
.subscribe(new Consumer<String>() {
// 成功返回数据时调用
@Override
public void accept(String combine_infro) throws Exception {
// 结合显示2个网络请求的数据结果
Log.d(TAG, "最终接收到的数据是:" + combine_infro);
}
}, new Consumer<Throwable>() {
// 网络请求错误时调用
@Override
public void accept(Throwable throwable) throws Exception {
System.out.println("登录失败");
}
});
5、联合判断多个事件
/*
* 步骤2:为每个EditText设置被观察者,用于发送监听事件
* 说明:
* 1. 此处采用了RxBinding:RxTextView.textChanges(name) = 对控件数据变更进行监听(功能类似TextWatcher),
需要引入依赖:compile 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
* 2. 传入EditText控件,点击任1个EditText输入时,都会发送数据事件 = Function3()的返回值(下面会详细说明)
* 3. 采用skip(1)原因:跳过 一开始 EditText无任何输入时的空值
*/
Observable<CharSequence> nameObservable = RxTextView.textChanges(name).skip(1);
Observable<CharSequence> ageObservable = RxTextView.textChanges(age).skip(1);
Observable<CharSequence> jobObservable = RxTextView.textChanges(job).skip(1);
/*
* 步骤3:通过combineLatest()合并事件 & 联合判断
*/
Observable.combineLatest(nameObservable,ageObservable,jobObservable,new Function3<CharSequence, CharSequence, CharSequence,Boolean>() {
@Override
public Boolean apply(@NonNull CharSequence charSequence, @NonNull CharSequence charSequence2, @NonNull CharSequence charSequence3) throws Exception {
/*
* 步骤4:规定表单信息输入不能为空
**/
// 1. 姓名信息
boolean isUserNameValid = !TextUtils.isEmpty(name.getText()) ;
// 除了设置为空,也可设置长度限制
// boolean isUserNameValid = !TextUtils.isEmpty(name.getText()) && (name.getText().toString().length() > 2 && name.getText().toString().length() < 9);
// 2. 年龄信息
boolean isUserAgeValid = !TextUtils.isEmpty(age.getText());
// 3. 职业信息
boolean isUserJobValid = !TextUtils.isEmpty(job.getText()) ;
/*
* 步骤5:返回信息 = 联合判断,即3个信息同时已填写,"提交按钮"才可点击
**/
return isUserNameValid && isUserAgeValid && isUserJobValid;
}})
.subscribe(new Consumer<Boolean>() {
@Override
public void accept(Boolean s) throws Exception {
/*
* 步骤6:返回结果 & 设置按钮可点击样式
**/
Log.e(TAG, "提交按钮是否可点击: "+s);
list.setEnabled(s);
}
});
===================== 后面内容可看额不看 ====================
详细说明
4、使用步骤
1)创建被观察者(Observable) & 生产事件
// 1. 创建被观察者 Observable 对象
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
/* create() 是 RxJava 最基本的创造事件序列的方法
* 此处传入了一个 OnSubscribe 对象参数
* 当 Observable 被订阅时,OnSubscribe 的 call() 方法会自动被调用,即事件序列就会依照设定依次被触发
* 即观察者会依次调用对应事件的复写方法从而响应事件
* 从而实现被观察者调用了观察者的回调方法 & 由被观察者向观察者的事件传递,即观察者模式
*/
// 2. 在复写的subscribe()里定义需要发送的事件
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
/* 通过 ObservableEmitter 类对象产生事件并通知观察者
* ObservableEmitter类介绍
* a. 定义:事件发射器
* b. 作用:定义需要发送的事件 & 向观察者发送事件
*/
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
});
方法1:just(T…):【直接将传入的参数依次发送出来】
Observable observable = Observable.just("A", "B", "C");
/* 将会依次调用:
* onNext("A");
* onNext("B");
* onNext("C");
* onCompleted();
*/
方法2:from(T[]) / from(Iterable<? extends T>) 【将传入的数组 / Iterable 拆分成具体对象后,依次发送出来】
String[] words = {"A", "B", "C"};
Observable observable = Observable.from(words);
/* 将会依次调用:
* onNext("A");
* onNext("B");
* onNext("C");
* onCompleted();
*/
2)创建观察者(Observer) 并 定义响应事件行为
事件类型包括:Next 事件、 Complete 事件 & Error 事件。
-
i.Next 普通事件
向观察者发送需要响应事件的信号
被观察者可发送无限个Next 事件;观察者可接收无限个Next 事件
onNext() -
ii.Complete 事件队列完结 事件;(RxJava 把所有事件当作队列处理)
标志 被观察者 不再发送普通事件(Next)
当 被观察者 发送要给Complete 事件后:
被观察者在Complete 事件后的事件,将会继续发送,
但观察者收到 Complete 事件后,将不再继续接收任何事件。被观察者 可以不发送Complete 事件
onComplete() -
iii.Error 事件队列异常 事件
标志 事件处理过程中出现异常(此时队列自动终止,不允许再有事件发送)当 被观察者 发送一个 Error 事件后:
被观察者在 Error事件后的事件将会继续发送,
但观察者收到Error事件后,将不再继续接收任何事件。被观察者 可以不发送Error 事件
onError() -
iv.在要给正确运行的事件序列中:
onComplete() & onError() 二者互斥
onComplete() & onError() 是唯一的
方式一:创建观察者 (Observer )对象,实现 onSubscribe() 方法
观察者接收事件前,默认最先调用复写 onSubscribe()
Observer<Integer> observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "开始采用subscribe连接");
}
// 当被观察者生产 Next事件 & 观察者接收到时,会调用该复写方法 进行响应
@Override
public void onNext(Integer value) {
Log.d(TAG, "对Next事件作出响应" + value);
}
// 当被观察者生产Error事件& 观察者接收到时,会调用该复写方法 进行响应
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应");
}
// 当被观察者生产Complete事件& 观察者接收到时,会调用该复写方法 进行响应
@Override
public void onComplete() {
Log.d(TAG, "对Complete事件作出响应");
}
};
方式2:采用 Subscriber 抽象类
Subscriber类 = RxJava 内置的一个实现了 Observer 的抽象类,对 Observer 接口进行了扩展
观察者接收事件前,默认最先调用复写 onSubscribe()
Subscriber<Integer> subscriber = new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, "开始采用subscribe连接");
}
// 当被观察者生产Next事件 & 观察者接收到时,会调用该复写方法 进行响应
@Override
public void onNext(Integer value) {
Log.d(TAG, "对Next事件作出响应" + value);
}
// 当被观察者生产Error事件& 观察者接收到时,会调用该复写方法 进行响应
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应");
}
// 当被观察者生产Complete事件& 观察者接收到时,会调用该复写方法 进行响应
@Override
public void onComplete() {
Log.d(TAG, "对Complete事件作出响应");
}
};
Subscriber 抽象类与 Observer 接口的区别:
-
相同点:二者基本使用方式完全一致
在RxJava的 subscribe 过程中,Observer总是会先被转换成 Subscriber 再使用 -
不同点:Subscriber抽象类对 Observer 接口进行了扩展,新增了两个方法:
-
onStart():响应事件前调用 ,用于做一些 初始化工作
-
unsubscribe():用于取消订阅。 在该方法被调用后,观察者将不再接收 & 响应事件
调用该方法前,先使用 isUnsubscribed() 判断状态,
确定被观察者 Observable 是否还持有观察者 Subscriber 的引用,
如果引用不能及时释放,就会出现内存泄露
-
-
3)通过订阅(Subscribe) 连接观察者和被观察者
具体实现:
observable.subscribe(observer);
或者
observable.subscribe(subscriber);Observable.subscribe(Subscriber) 的内部实现:
public Subscription subscribe(Subscriber subscriber) { // 步骤1中 观察者 subscriber抽象类复写的方法,用于初始化工作 subscriber.onStart(); /* 通过该调用,从而回调观察者中的对应方法,从而响应被观察者生产的事件 * 从而实现被观察者调用了观察者的回调方法 & 由被观察者向观察者的事件传递,即观察者模式 * * 同时也看出:Observable只是生产事件,真正的发送事件是在它被订阅的时候 * 即当 subscribe() 方法执行时 */ onSubscribe.call(subscriber); }
5、基于事件流的链式调用
// RxJava的链式操作
Observable.create(new ObservableOnSubscribe<Integer>() {
// 1. 创建被观察者 & 生产事件
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
//emitter 是事件发射器
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
// 2. 通过通过订阅(subscribe)连接观察者和被观察者
}).subscribe(new Observer<Integer>() {// 3. 创建观察者 & 定义响应事件的行为
// 默认最先调用复写的 onSubscribe()
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "开始采用subscribe连接");
}
@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事件作出响应");
}
});
【整体方法调用顺序】:
观察者.onSubscribe() > 被观察者.subscribe() > 观察者.onNext() > 观察者.onComplete()
6、多个函数式接口,实现更便捷的观察者模式
Action、BiConsumer、BiFunction、Cancellable、Consumer、Function、Function3…
Observable.just("hello").subscribe(new Consumer<String>() {
// 每次接收到 Observable 的事件都会调用 Consumer.accept()
@Override
public void accept(String s) throws Exception、
System.out.println(s);
}
});
7、被观察者 Observable 的 subscribe() 具备多个重载的方法
-
1)多个重载方法的说明
subscribe() 无参数,表示被观察者可以发送事件,观察者对事件【不作出任何响应】
public final Disposable subscribe() {}
表示 观察者只对【Next事件】作出响应
public final Disposable subscribe(Consumer<? super T> onNext) {}
表示 观察者只对【Next事件 & Error事件】作出响应
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {}
表示 观察者只对【Next事件、Error事件 & Complete事件】作出响应
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
表示 观察者只对【Next事件、Error事件 、Complete事件 & onSubscribe事件】作出响应
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
表示 观察者对任何事件都作出响应
public final void subscribe(Observer<? super T> observer) {}
-
2)采用 Disposable.dispose() 切断观察者 与 被观察者 之间的连接
观察者 无法继续 接收 被观察者的事件,但被观察者可以继续发送事件
// 主要在观察者 Observer中 实现 Observer<Integer> observer = new Observer<Integer>() { // 1. 定义Disposable类变量 private Disposable mDisposable; @Override public void onSubscribe(Disposable d) { Log.d(TAG, "开始采用subscribe连接"); // 2. 对Disposable类变量赋值 mDisposable = d; } @Override public void onNext(Integer value) { Log.d(TAG, "对Next事件"+ value +"作出响应" ); if (value == 2) {// 设置在接收到第二个事件后切断观察者和被观察者的连接 mDisposable.dispose(); Log.d(TAG, "已经切断了连接:" + mDisposable.isDisposed()); } } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } };
二、RxJava常用【创建操作符】 create、just、from、interval、range等
1、create() 创建一个被观察者对象(Observable)
/** 通过create()创建被观察者 Observable 对象
* 传入参数: OnSubscribe 对象
*
* 当 Observable 被订阅时,OnSubscribe 的 call() 方法会自动被调用,即事件序列就会依照设定依次被触发
* 即观察者会依次调用对应事件的复写方法从而响应事件
* 从而实现由被观察者向观察者的事件传递 & 被观察者调用了观察者的回调方法 ,即观察者模式
*/
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
// 2. 在复写的subscribe() 里定义【需要发送的事件】
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
// 通过 ObservableEmitter类对象 产生 & 发送事件
// ObservableEmitter类介绍
// a. 定义:事件发射器
// b. 作用:定义需要发送的事件 & 向观察者发送事件
// 注:建议发送事件前检查观察者的isUnsubscribed状态,以便在没有观察者时,让Observable停止发射数据
if (!observer.isUnsubscribed()) {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
emitter.onComplete();
}
});
2、just() 快速创建被观察者对象,直接发送传入的事件,最多只能发送10个参数
场景:快速创建 被观察者对象(Observable) & 发送10个以下事件
// 1.创建时传入整型1、2、3、4
// 在创建后就会发送这些对象,相当于执行了onNext(1)、onNext(2)、onNext(3)、onNext(4)
Observable.just(1, 2, 3,4)
// 至此,一个Observable对象创建完毕,以下步骤仅为展示一个完整demo,可以忽略
// 2. 通过通过订阅(subscribe)连接观察者和被观察者
// 3. 创建观察者 & 定义响应事件的行为
.subscribe(new Observer<Integer>() {
...
});
3、fromArray()
快速创建1个被观察者对象,直接发送传入的数组数据,会将数组中的数据转为 Observable 对象
场景:1)快速创建 被观察者对象(Observable) & 发送10个以上事件(数组形式)
2)数组元素遍历
// 1. 设置需要传入的数组
Integer[] items = { 0, 1, 2, 3, 4 };
// 2. 创建被观察者对象(Observable)时传入数组,在创建后就会将该数组转换成 Observable & 发送该对象中的所有数据
Observable.fromArray(items)
.subscribe(...);
注:若直接传递一个list集合进去,否则会直接把list当做一个数据元素发送
4、fromIterable()
快速创建1个被观察者对象(Observable),直接发送 传入的集合List数据
场景:1)快速创建 被观察者对象(Observable) & 发送10个以上事件(集合形式)
2)集合元素遍历
Observable.fromIterable(list)
.subscribe(...);
5、empty()
/*该方法创建的被观察者对象发送事件的特点:仅发送Complete事件,直接通知完成
* 观察者接收后会直接调用onCompleted()
*/
Observable observable = Observable.empty();
6、error()
/* 该方法创建的被观察者对象发送事件的特点:仅发送Error事件,直接通知异常
* 可自定义异常,观察者接收后会直接调用onError()
*/
Observable observable = Observable.error(new RuntimeException())
7、never()
/* 该方法创建的被观察者对象发送事件的特点:不发送任何事件
* 观察者接收后什么都不调用
*/
Observable observable = Observable.never();
8、defer() 延迟创建 Observable
直到有观察者(Observer)订阅时,才动态创建被观察者对象(Observable) & 发送事件
场景:动态创建被观察者对象(Observable) & 获取最新的 Observable 对象数据
// 1. 第1次对i赋值
Integer i = 10;
// 2. 通过defer 定义被观察者对象,此时被观察者对象还没创建
Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> call() throws Exception {
return Observable.just(i);
}
});
// 2. 第2次对i赋值,因为是在订阅时才创建,所以i值会取第2次的赋值
i = 15;
// 3. 观察者开始订阅,此时,才会调用defer()创建被观察者对象(Observable)
observable.subscribe(...);
9、timer()
快速创建1个被观察者对象(Observable),延迟指定时间后,调用一次 onNext(0)
场景:延迟指定时间,发送一个0 (Long类型),一般用于检测
timer()操作符默认运行在一个新线程上
可自定义线程调度器(第3个参数):timer(long,TimeUnit,Scheduler)
// 该例子 = 延迟2s后,发送一个long类型数值
Observable.timer(2, TimeUnit.SECONDS)
.subscribe(new Observer<Long>() {
...
});
10、interval()
快速创建1个被观察者对象(Observable),每隔指定时间 就发送 事件
发送的事件序列 = 从0开始、无限递增1的的整数序列
interval()默认在computation调度器上执行
可自定义指定线程调度器(第3个参数):interval(long,TimeUnit,Scheduler)
/* 参数说明:
* 参数1 = 第1次延迟时间;
* 参数2 = 间隔时间数字;
* 参数3 = 时间单位;
*/
Observable.interval(3 ,1 ,TimeUnit.SECONDS)
// 该例子发送的事件序列特点:延迟3s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
.subscribe(new Observer<Long>() {
...
});
11、intervalRange()
快速创建1个被观察者对象(Observable),每隔指定时间 就发送 事件,可指定发送的数据的数量
a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
b. 作用类似于interval(),但可指定发送的数据的数量
/* 参数说明:
* 参数1 = 事件序列起始点;
* 参数2 = 事件数量;
* 参数3 = 第1次事件延迟发送时间;
* 参数4 = 间隔时间数字;
* 参数5 = 时间单位
*/
Observable.intervalRange(3 ,10 , 2, 1, TimeUnit.SECONDS)
/* 该例子发送的事件序列特点:
* 1. 从3开始,一共发送10个事件;
* 2. 第1次延迟2s发送,之后每隔2秒产生1个数字(从0开始递增1,无限个)
*/
.subscribe(new Observer<Long>() {
...
});
12、range()
快速创建1个被观察者对象(Observable),连续发送 1 个事件序列,可指定范围
a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
b. 作用类似于intervalRange(),但区别在于:无延迟发送事件
/* 参数说明:
* 参数1 = 事件序列起始点;
* 参数2 = 事件数量;
* 注:若设置为负数,则会抛出异常
*/
Observable.range(3 ,10)
// 该例子发送的事件序列特点:从3开始发送,每次发送事件递增1,一共发送10个事件
.subscribe(new Observer<Integer>() {
...
});
13、rangeLong()
类似 range(),区别在于该操作符支持数据类型 = Long
使用方式与 range()类似。
三、RxJava常用变换操作符 map()、flatMap()、concatMap()、buffer()
1、map()
将被观察者发送的事件转换为任意的类型事件
场景:数据类型转换
//创建被观察者
Observable.create(new ObservableOnSubscribe<Integer>() {
// 1. 被观察者发送事件 = 参数为整型 = 1、2、3
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
// 2. 使用Map变换操作符中的Function函数对被观察者发送的事件进行统一变换:整型变换成字符串类型
}).map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return "使用 Map变换操作符 将事件" + integer +"的参数从 整型"+integer + " 变换成 字符串类型" + integer ;
}
}).subscribe(new Consumer<String>() {
// 3. 观察者接收事件时,是接收到变换后的事件 = 字符串类型
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
2、flatMap()
将被观察者发送的事件进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送。
场景:无序的将被观察者的整个事件序列进行变换。
【新合并生成的事件序列顺序是无序的,即 与旧序列发送事件的顺序无关】
步骤:
i.为事件序列中每个事件都创建一个 Observable 对象
ii.将对每个 原始事件 转换后的 新事件,都放入到对应 Observable 对象
iii.将新建的每个 Observable 都合并到一个新建的、总的 Observable 对象
iv.新建的、总的 Observable 对象,将 新合并的事件序列,发送给观察者。
// 创建被观察者
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
// 采用flatMap()变换操作符
}).flatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
final List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
// 通过flatMap中,将被观察者生产的事件序列先进行拆分
// 再将每个事件转换为一个新的发送三个String事件
// 最终合并,再发送给被观察者
list.add("我是事件 " + integer + "拆分后的子事件" + i);
}
return Observable.fromIterable(list);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
3、concatMap()
作用类似flatMap()操作符
与flatMap()区别:拆分 & 重新合并生成的 事件序列 的顺序 = 被观察者旧序列生产的顺序。
场景:有序的将被观察者发送的整个事件序列进行转换
【新合并生成的事件序列顺序是有序的,即 严格按照旧序列发送事件的顺序】
// 创建被观察者
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
// 采用concatMap()变换操作符
}).concatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
// 通过concatMap中将被观察者生产的事件序列先进行拆分,
// 再将每个事件转换为一个新的发送三个String事件
// 最终合并,再发送给被观察者
final List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("我是事件 " + integer + "拆分后的子事件" + i);
}
return Observable.fromIterable(list);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
4、buffer()
定期从 被观察者(Obervable)需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送
场景:缓存 被观察者 发送的事件。
// 被观察者 需要发送5个数字
Observable.just(1, 2, 3, 4, 5)
/* 设置缓存区大小 & 步长
* 缓存区大小 = 每次从被观察者中获取的事件数量
* 步长 = 每次获取新事件的数量
*/
.buffer(3, 1)
.subscribe(new Observer<List<Integer>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<Integer> stringList) {
//
Log.d(TAG, " 缓存区里的事件数量 = " + stringList.size());
for (Integer value : stringList) {
Log.d(TAG, " 事件 = " + value);
}
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应" );
}
@Override
public void onComplete() {
Log.d(TAG, "对Complete事件作出响应");
}
});
这里表示,每次从Observable 中获取3条数据放到缓冲区中发送。
每发送完一次,向右偏移1位,继续从Observable 中获取数据。
结果:
第一次,缓存区事件数量3,事件1、2、3
第二次,缓存区事件数量3,事件2、3、4
第三次,缓存区事件数量3,事件3、4、5
第四次,缓存区事件数量2,事件4、5
第五次,缓存区事件数量1,事件5
对Complete事件作出响应
四、RxJava常用组合、合并操作符 combineLatest、join、merge、zip等
组合操作符:组合多个被观察者(Observable) & 合并需要发送的事件
1、组合多个被观察者
1)按发送顺序 concat()、concatArray()
组合多个被观察者一起发送数据,合并后 【按发送顺序 串行执行】
concat()组合被观察者数量 <= 4个,而concatArray()则可 > 4个
// concat():组合多个被观察者(≤4个)一起发送数据,串行执行
Observable.concat(Observable.just(1, 2, 3),
Observable.just(4, 5, 6),
Observable.just(7, 8, 9),
Observable.just(10, 11, 12))
.subscribe(new Observer<Integer>() {
...
});
// concatArray():组合多个被观察者一起发送数据(可>4个),串行执行
Observable.concatArray(Observable.just(1, 2, 3),
Observable.just(4, 5, 6),
Observable.just(7, 8, 9),
Observable.just(10, 11, 12),
Observable.just(13, 14, 15))
.subscribe(new Observer<Integer>() {
...
});
2)按时间 merge()、mergeArray()
组合多个被观察者一起发送数据,合并后 【按时间线 并行执行】
merge()组合被观察者数量≤4个,而mergeArray() 则可>4个
// merge():组合多个被观察者(<= 4个)一起发送数据
// 注:合并后按照时间线并行执行
Observable.merge(
// 从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
// 从2开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS))
.subscribe(new Observer<Long>() {
/* 输出结果:
* 两个被观察者发送事件并行执行
* 输出结果 = 0,2 -> 1,3 -> 2,4
*/
...
});
// mergeArray() = 组合4个以上的被观察者一起发送数据,此处不作过多演示,类似concatArray()
3)错误处理 concatDelayError()、mergeDelayError()
使用 concat()、merge()操作符时,若其中一个被观察者发出onError()事件,
则会马上终止其他被观察者继续发送事件。
若希望onError()事件推迟到其他被观察者发送事件结束后才触发,
需要使用对应的 concatDelayError()、mergeDelayError()操作符。
Observable.concatArrayDelayError(
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
// 发送Error事件,因为使用了concatDelayError,所以第2个Observable将会发送事件,
// 等发送完毕后,再发送错误事件
emitter.onError(new NullPointerException());
emitter.onComplete();
}
}),
Observable.just(4, 5, 6))
.subscribe(new Observer<Integer>() {
//结果:第1个被观察者的Error事件,将在第2个被观察者发送完事件后再继续发送
// 1、2、3、4、5、6、Error
...
});
2、合并多个事件
对多个被观察者中的【事件】进行合并处理
1)按数量 zip()
合并 多个 Observable 发送的事件,生成一个新的事件序列(即组合过后的事件序列)
并最终发送。
事件组合方式 = 严格按照原先事件序列 进行对位合并
合并后新 Observable 的事件数量 = 多个被观察者(Observable)中 数量最少 的数量
场景:不同数据源的数据,需要统一结合后再处理。
【1】创建第1个被观察者
Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Log.d(TAG, "被观察者1发送了事件1");
emitter.onNext(1);
// 为了方便展示效果,所以在发送事件后加入1s的延迟
Thread.sleep(1000);
Log.d(TAG, "被观察者1发送了事件2");
emitter.onNext(2);
Thread.sleep(1000);
Log.d(TAG, "被观察者1发送了事件3");
emitter.onNext(3);
Thread.sleep(1000);
emitter.onComplete();
}
}).subscribeOn(Schedulers.io()); // 设置被观察者1在工作线程1中工作
【2】创建第2个被观察者
Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d(TAG, "被观察者2发送了事件A");
emitter.onNext("A");
Thread.sleep(1000);
Log.d(TAG, "被观察者2发送了事件B");
emitter.onNext("B");
Thread.sleep(1000);
Log.d(TAG, "被观察者2发送了事件C");
emitter.onNext("C");
Thread.sleep(1000);
Log.d(TAG, "被观察者2发送了事件D");
emitter.onNext("D");
Thread.sleep(1000);
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread());// 设置被观察者2在工作线程2中工作
// 假设不作线程控制,则该两个被观察者会在同一个线程中工作,
// 即发送事件存在先后顺序,而不是同时发送
【3】使用zip变换操作符进行事件合并
// 注:创建BiFunction对象传入的第3个参数 = 合并后数据的数据类型
Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String string) throws Exception {
return integer + string;
}
}).subscribe(new Observer<String>() {
//1、尽管被观察者2的 事件D 没有事件与其合并,但还是会继续发送
//2、若在被观察者1 & 被观察者2的事件序列最后发送onComplete()事件,
// 则被观察者2的事件D也不会发送
...
});
2)按时间 combineLatest()、combineLatestDelayError()
i.combineLatest()
当两个 Observable 中的任何一个发送了数据后,
将先发送了数据的 Observables 的最新(最后)一个数据 与 另外一个Observable发送的每个数据结合,
最终基于该函数的结果发送数据
与zip()的区别:zip() = 按个数合并,即 1对1 合并;
combineLatest() = 按时间合并,即在同一个时间点上合并
Observable.combineLatest(
// 第1个发送数据事件的 Observable
Observable.just(1L, 2L, 3L),
// 第2个发送数据事件的Observable:从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
new BiFunction<Long, Long, Long>() {
@Override
public Long apply(Long o1, Long o2) throws Exception {
// o1 = 第1个 Observable 发送的最新(最后)1个数据
// o2 = 第2个Observable发送的每1个数据
Log.e(TAG, "合并的数据是: "+ o1 + " "+ o2);
return o1 + o2;
// 合并的逻辑 = 相加
// 即第1个Observable发送的最后1个数据 与 第2个Observable发送的每1个数据进行相加
}
}).subscribe(new Consumer<Long>() {
@Override
public void accept(Long s) throws Exception {
/* 结果:
合并的数据是:3 0
合并的结果是:3
合并的数据是:3 1
合并的结果是:4
合并的数据是:3 2
合并的结果是:5
*/
Log.e(TAG, "合并的结果是: "+s);
}
});
ii.combineLatestDelayError()
类似于concatDelayError() / mergeDelayError() ,即错误处理。
一个 被观察者的onError()事件,延迟到另一个 被观察者的事件发送完之后再发送。
3)合并成1个事件发送 reduce()、collect()
i.reduce()
把被观察者需要发送的事件聚合成1个事件 & 发送
聚合的逻辑根据需求撰写,但本质都是【前2个数据聚合,然后与后1个数据继续进行聚合】,依次类推
Observable.just(1,2,3,4)
.reduce(new BiFunction<Integer, Integer, Integer>() {
// 在该复写方法中复写聚合的逻辑
@Override
public Integer apply(@NonNull Integer s1, @NonNull Integer s2) throws Exception {
Log.e(TAG, "本次计算的数据是: "+s1 +" 乘 "+ s2);
return s1 * s2;
// 本次聚合的逻辑是:全部数据相乘起来
// 原理:第1次取前2个数据相乘,
// 之后每次获取到的数据 = 返回的数据x原始下1个数据
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer s) throws Exception {
/*结果:
本次计算的数据是:1 乘 2
本次计算的数据是:2 乘 3
本次计算的数据是:6 乘 4
最终计算的结果是:24
*/
Log.e(TAG, "最终计算的结果是: "+s);
}
});
ii.collect()
将被观察者 Observable 发送的数据事件收集到一个数据结构里
Observable.just(1, 2, 3 ,4, 5, 6)
// 1. 创建数据结构(容器),用于收集被观察者发送的数据
.collect(new Callable<ArrayList<Integer>>() {
@Override
public ArrayList<Integer> call() throws Exception {
return new ArrayList<>();
}
// 2. 对发送的数据进行收集
}, new BiConsumer<ArrayList<Integer>, Integer>() {
@Override
public void accept(ArrayList<Integer> list, Integer integer) throws Exception {
// 参数说明:list = 容器,integer = 后者数据
list.add(integer);
// 对发送的数据进行收集
}
}).subscribe(new Consumer<ArrayList<Integer>>() {
@Override
public void accept(@NonNull ArrayList<Integer> s) throws Exception {
Log.e(TAG, "本次发送的数据是: "+s);
//结果:本次发送的数据是:[1,2,3,4,5,6]
}
});
3、发送事件前追加发送事件
startWith()/startWithArray()
在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者
1)在一个被观察者发送事件前,追加发送一些数据
// 注:追加数据顺序 = 后调用先追加
Observable.just(4, 5, 6)
.startWith(0) // 追加单个数据 = startWith()
.startWithArray(1, 2, 3) // 追加多个数据 = startWithArray()
.subscribe(new Observer<Integer>() {
...
/* 结果:
接收到了事件 1
接收到了事件 2
接收到了事件 3
接收到了事件 0
接收到了事件 4
接收到了事件 5
接收到了事件 6
*/
});
2)在一个被观察者发送事件前,追加发送被观察者 & 发送数据
// 注:追加数据顺序 = 后调用先追加
Observable.just(4, 5, 6)
.startWith(Observable.just(1, 2, 3))
.subscribe(new Observer<Integer>() {
...
/* 结果:
接收到了事件 1
接收到了事件 2
接收到了事件 3
接收到了事件 4
接收到了事件 5
接收到了事件 6
*/
});
4、统计发送事件数量
1)count()
统计被观察者【发送事件的数量】
// 注:返回结果 = Long类型
Observable.just(1, 2, 3, 4)
.count()
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Log.e(TAG, "发送的事件数量 = "+aLong);
//结果:发送的事件数量 4
}
});
五、功能性操作符
1、连接被观察者 & 观察者
订阅:subscribe()
//通过订阅(subscribe)连接观察者和被观察者
observable.subscribe(observer);
2、线程调度
subscribeOn() 设置被观察者执行的线程
observeOn() 设置观察者执行的线程
场景:快速、方便指定 & 控制被观察者 & 观察者 的工作线程
类型 含义 应用场景
----------------------------------------------------------------------
Schedulers.immediate() 当前线程 = 不指定线程 默认
----------------------------------------------------------------------
AndroidSchedulers.mainThread() Android主线程 操作UI
----------------------------------------------------------------------
Schedulers.newThread() 常规新线程 耗时等操作
----------------------------------------------------------------------
Schedulers.io() io操作线程 网络请求、读写文件等io密集型操作
----------------------------------------------------------------------
Schedulers.computation() CPU计算操作线程 大量计算操作
RxJava内部使用【线程池】来维护这些线程,所以线程的调度效率非常高。
observable.subscribeOn(Schedulers.newThread()) // 1. 指定被观察者 生产事件的线程
.observeOn(AndroidSchedulers.mainThread()) // 2. 指定观察者 接收 & 响应事件的线程
.subscribe(observer); // 3. 最后再通过订阅(subscribe)连接观察者和被观察者
3、延迟操作
delay()
使得被观察者延迟一段时间再发送事件
Observable.just(1, 2, 3)
.delay(3, TimeUnit.SECONDS) // 延迟3s再发送,由于使用类似,所以此处不作全部展示
.subscribe(new Observer<Integer>() {
...
});
4、在事件的生命周期中操作
do()
场景:在事件发送 & 接收的整个生命周期过程中进行操作
如发送事件前的初始化、发送事件后的回调请求等
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
e.onError(new Throwable("发生错误了"));
}
})
// 1. 当Observable 每发送1次数据事件,就会调用1次
.doOnEach(new Consumer<Notification<Integer>>() {
@Override
public void accept(Notification<Integer> integerNotification) throws Exception {
Log.d(TAG, "doOnEach: " + integerNotification.getValue());
}
})
// 2. 执行Next事件前调用
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "doOnNext: " + integer);
}
})
// 3. 执行Next事件后调用
.doAfterNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "doAfterNext: " + integer);
}
})
// 4. Observable正常发送事件完毕后调用
.doOnComplete(new Action() {
@Override
public void run() throws Exception {
Log.e(TAG, "doOnComplete: ");
}
})
// 5. Observable发送错误事件时调用
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.d(TAG, "doOnError: " + throwable.getMessage());
}
})
// 6. 观察者订阅时调用
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(@NonNull Disposable disposable) throws Exception {
Log.e(TAG, "doOnSubscribe: ");
}
})
// 7. Observable 发送事件完毕后调用,无论正常发送完毕 / 异常终止
.doAfterTerminate(new Action() {
@Override
public void run() throws Exception {
Log.e(TAG, "doAfterTerminate: ");
}
})
// 8. 最后执行
.doFinally(new Action() {
@Override
public void run() throws Exception {
Log.e(TAG, "doFinally: ");
}
})
.subscribe(new Observer<Integer>() {
...
/*结果:
doOnSubscribe
doOnEach 1
doOnNext 1
接收到事件 1
doAfterNext 1
doOnEach 2
doOnNext 2
接收到事件 2
doAfterNext 2
doOnEach 3
doOnNext 3
接收到事件 3
doAfterNext 3
doOnEach null
doOnError 发送错误了
对Error事件做出响应
doFinally
doAfterTerminate
*/
});
5、错误处理
1)onErrorReturn()
发送事件过程中,遇到错误时的处理机制
可捕获再它之前发生的异常
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Throwable("发生错误了"));
}
}).onErrorReturn(new Function<Throwable, Integer>() {
@Override
public Integer apply(@NonNull Throwable throwable) throws Exception {
// 捕捉错误异常
Log.e(TAG, "在onErrorReturn处理了错误: "+throwable.toString() );
// 发生错误事件后,发送一个"666"事件,最终正常结束
return 666;
}
})
.subscribe(new Observer<Integer>() {
...
});
2)onErrorResumeNext()
遇到错误时,发送1个新的Observable
onErrorResumeNext() 拦截的错误 = Throwable;若需拦截Exception请用onExceptionResumeNext()
若 onErrorResumeNext() 拦截的错误 = Exception,则会将错误传递给观察者的 onError 方法
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Throwable("发生错误了"));
}
}).onErrorResumeNext(new Function<Throwable, ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> apply(@NonNull Throwable throwable) throws Exception {
// 1. 捕捉错误异常
Log.e(TAG, "在onErrorReturn处理了错误: "+throwable.toString() );
// 2. 发生错误事件后,发送一个新的被观察者 & 发送事件序列
return Observable.just(11,22);
}
})
.subscribe(new Observer<Integer>() {
...
});
3)onExceptionResumeNext()
遇到错误时,发送1个新的Observable
onExceptionResumeNext() 拦截的错误 = Exception;若需拦截Throwable请用onErrorResumeNext()
若onExceptionResumeNext() 拦截的错误 = Throwable,则会将错误传递给观察者的 onError方法
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Exception("发生错误了"));
}
}).onExceptionResumeNext(new Observable<Integer>() {
@Override
protected void subscribeActual(Observer<? super Integer> observer) {
observer.onNext(11);
observer.onNext(22);
observer.onComplete();
}
})
.subscribe(new Observer<Integer>() {
...
});
4)retry()
重试,即当出现错误时,让被观察者(Observable)重新发射数据
接收到 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) -->
// 作用:出现错误后,判断是否需要重新发送数据(具备重试次数限制)
// 参数 = 设置重试次数 & 判断逻辑
// 拦截错误后,判断是否需要重新发送请求
.retry(new Predicate<Throwable>() {
@Override
public boolean test(@NonNull Throwable throwable) throws Exception {
// 捕获异常
Log.e(TAG, "retry错误: "+throwable.toString());
//返回false = 不重新重新发送数据 & 调用观察者的onError结束
//返回true = 重新发送请求(若持续遇到错误,就持续重新发送)
return true;
}
})
// 拦截错误后,判断是否需要重新发送请求
.retry(new BiPredicate<Integer, Throwable>() {
@Override
public boolean test(@NonNull Integer integer, @NonNull Throwable throwable) throws Exception {
// 捕获异常
Log.e(TAG, "异常错误 = "+throwable.toString());
// 获取当前重试次数
Log.e(TAG, "当前重试次数 = "+integer);
//返回false = 不重新重新发送数据 & 调用观察者的onError结束
//返回true = 重新发送请求(若持续遇到错误,就持续重新发送)
return true;
}
})
/* 拦截错误后,判断是否需要重新发送请求
* 参数一:重试次数
* 参数二:判断是否需要重新发送数据的逻辑
*/
.retry(3, new Predicate<Throwable>() {
@Override
public boolean test(@NonNull Throwable throwable) throws Exception {
// 捕获异常
Log.e(TAG, "retry错误: "+throwable.toString());
//返回false = 不重新重新发送数据 & 调用观察者的onError()结束
//返回true = 重新发送请求(最多重新发送3次)
return true;
}
})
5)retryUntil()
出现错误后,判断是否需要重新发送数据
若需要重新发送 & 持续遇到错误,则持续重试
作用类似于retry(Predicate predicate)
具体使用类似于retry(Predicate predicate),唯一区别:返回 true 则不重新发送数据事件
6)retryWhen()
遇到错误时,将发生的错误传递给一个新的被观察者(Observable),
并决定是否需要重新订阅原始被观察者(Observable)& 发送事件
// 遇到 error 事件才会回调
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
/*参数 Observable<Throwable> 中的泛型 = 上游操作符抛出的异常,可通过该条件来判断异常的类型
*返回 Observable<?> = 新的被观察者 Observable(任意类型)
*
*此处有两种情况:
* 1.若 新的被观察者 Observable发送的事件 = Error事件,那么 原始Observable则不重新发送事件:
* 2.若 新的被观察者 Observable发送的事件 = Next事件 ,那么原始的Observable则重新发送事件:
*/
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {
//IOException时,返回onNext(null),原始的Observable 重新发送事件
if (error instanceof IOException) {
return Observable.just(null);
}
//其他异常,发送onError()事件,不会再重试
return Observable.error(error);
}
});
}
})
6、重复发送 repeat()、repeatWhen()
(1).接收到.onCompleted()事件后,触发重新订阅 & 发送
(2).默认运行在一个新的线程上
1)repeat()
// 不传入参数 = 重复发送次数 = 无限次
repeat();
// 传入参数 = 重复发送次数有限
repeatWhen(Integer);
// 具体使用
Observable.just(1, 2, 3, 4)
.repeat(3) // 重复创建次数 =- 3次
.subscribe(new Observer<Integer>() {
...
});
2)repeatWhen()
有条件地、重复发送 被观察者事件
将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据
传递给1个新被观察者(Observable),以此决定是否重新订阅 & 发送原来的 Observable
若新被观察者(Observable)返回1个 Complete / Error 事件,则不重新订阅 & 发送原来的 Observable
若新被观察者(Observable)返回其余事件时,则重新订阅 & 发送原来的 Observable
Observable.just(1,2,4).repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
// 在 Function 函数中,必须对输入的 Observable<Object> 进行处理,
// 这里我们使用的是 flatMap 操作符接收上游的数据
@Override
public ObservableSource<?> apply(@NonNull Observable<Object> objectObservable) throws Exception {
/* 将原始 Observable 停止发送事件的标识(Complete()/Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable)
* 以此决定是否重新订阅 & 发送原来的 Observable
* 此处有2种情况:
* 1.若新被观察者(Observable)返回1个Complete()/Error()事件,则不重新订阅 & 发送原来的 Observable
* 2.若新被观察者(Observable)返回其余事件,则重新订阅 & 发送原来的 Observable
*/
return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Object throwable) throws Exception {
/* 情况1:若新被观察者(Observable)返回1个Complete()/Error()事件,则不重新订阅 & 发送原来的 Observable
*
* Observable.empty() = 发送Complete事件,但不会回调观察者的onComplete()
*/
return Observable.empty();
/* 返回Error事件 = 回调onError()事件,并接收传过去的错误信息。
* return Observable.error(new Throwable("不再重新订阅事件"));
*/
/* 情况2:若新被观察者(Observable)返回其余事件,则重新订阅 & 发送原来的 Observable
* return Observable.just(1);
* 仅仅是作为1个触发重新订阅被观察者的通知,发送的是什么数据并不重要,只要不是Complete()/Error()事件
*/
}
});
}
})
.subscribe(new Observer<Integer>() {
...
});
repeat()与retry()区别:
当.repeat()接收到.onCompleted()事件后触发重订阅。
当.retry()接收到.onError()事件后触发重订阅。
repeatWhen()与 retryWhen()的区别:
repeatWhen():若新被观察者(Observable)返回1个Complete()/Error()事件,则不重新订阅 & 发送原来的 Observable
retryWhen():新的被观察者 Observable发送的事件 = Error事件,那么 原始 Observable 则不重新发送事件:
六、RxJava过滤操作符 filter、ofType、sample、take 等
1、根据 指定条件 过滤事件
1)filter() 过滤 特定条件的事件
.filter(new Predicate<Integer>() {
/* 根据test()的返回值 对被观察者发送的事件进行过滤 & 筛选
* a. 返回true,则继续发送
* b. 返回false,则不发送(即过滤)
*/
@Override
public boolean test(Integer integer) throws Exception {
return integer > 3;
// 本例子 = 过滤了整数≤3的事件
}
})
2)ofType() 筛选出 特定数据类型的数据
Observable.just(1, "Carson", 3, "Ho", 5)
.ofType(Integer.class) // 筛选出 整型数据,其他类型的数据会被过滤掉
.subscribe(new Consumer<Integer>() {
@Override
public void accept( Integer integer) throws Exception {
Log.d(TAG,"获取到的整型事件元素是: "+ integer);
}
});
3)skip()/skipLast() 跳过某个事件
// 使用1:根据顺序跳过数据项
Observable.just(1, 2, 3, 4, 5)
.skip(1) // 跳过正序的前1项,过滤掉了1
.skipLast(2) // 跳过正序的后2项,过滤掉了4,5
.subscribe(new Consumer<Integer>() {
@Override
public void accept( Integer integer) throws Exception {
Log.d(TAG,"获取到的整型事件元素是: "+ integer);
}
});
// 使用2:根据时间跳过数据项
// 发送事件特点:发送数据,从0开始,共发送5个数据,也就是 0,1,2,3,4
// 每隔1s发送一次,每次递增1;第1次发送延迟0s
Observable.intervalRange(0, 5, 0, 1, TimeUnit.SECONDS)
.skip(1, TimeUnit.SECONDS) // 跳过第1s发送的数据,过滤掉了0
.skipLast(1, TimeUnit.SECONDS) // 跳过最后1s发送的数据,过滤掉了最后一条数据4
.subscribe(new Consumer<Long>() {
@Override
public void accept( Long along ) throws Exception {
Log.d(TAG,"获取到的整型事件元素是: "+ along);
}
});
4)distinct()/distinctUntilChanged()
过滤事件序列中重复的事件/连续重复的事件
// 使用1:过滤事件序列中重复的事件
Observable.just(1, 2, 3, 1 , 2 )
.distinct()//会过滤掉重复的 1,2
.subscribe(new Consumer<Integer>() {
@Override
public void accept( Integer integer) throws Exception {
Log.d(TAG,"不重复的整型事件元素是: "+ integer);
//结果:1,2,3
}
});
// 使用2:过滤事件序列中 连续重复的事件
// 下面序列中,连续重复的事件 = 3、4
Observable.just(1,2,3,1,2,3,3,4,4 )
.distinctUntilChanged()//过滤连续重复的3,4;非连续的不会过滤
.subscribe(new Consumer<Integer>() {
@Override
public void accept( Integer integer) throws Exception {
Log.d(TAG,"不连续重复的整型事件元素是: "+ integer);
//结果:1,2,3,1,2,3,4
}
});
2、根据 指定事件数量 过滤事件
场景:通过设置指定的事件数量,仅发送特定数量的事件
1)take() 指定观察者最多能接收到的事件数量
// 指定了观察者只能接收2个事件
observable.take(2)
2)takeLast() 指定观察者只能接收到被观察者发送的最后几个事件
//指定观察者只能接受被观察者发送的最后3个事件
observable.take(3)
3、根据 指定时间 过滤事件
通过设置指定的时间,仅发送在该时间内的事件
1)throttleFirst()/throttleLast()
在某段时间内,只发送该段时间内第1次事件 / 最后1次事件
/* 仅发送每1秒中,的第一个事件
* 比如,第一秒的第一个事件、第二秒的第一个事件、第三秒的第一个事件。
*/
observable.throttleFirst(1, TimeUnit.SECONDS)
/* 仅发送每1秒中,的最后一个事件
* 比如,第一秒的最后一个事件、第二秒的最后一个事件、第三秒的最后一个事件。
*/
observable.throttleLast(1, TimeUnit.SECONDS)
2)sample()
在某段时间内,只发送该段时间内最新(最后)1次事件,与 throttleLast() 操作符类似
3)throttleWithTimeout()/debounce()
发送数据事件时,若2次发送事件的间隔<指定时间,就会丢弃前一次的数据,
直到指定时间内都没有新数据发射时才会发送后一次的数据
//丢弃间隔小于指定时间1s 的前一次数据
observable.throttleWithTimeout(1, TimeUnit.SECONDS)
4、根据 指定事件位置 过滤事件
通过设置指定的位置,过滤在该位置的事件
1)firstElement()/lastElement()
仅选取第1个元素 / 最后一个元素
//获取第一个元素
observable.firstElement()
//获取最后一个元素
observable.lastElement()
2)elementAt( index )
指定接收某个元素(通过 索引值 确定),位置索引从0开始
允许越界,即 获取的位置索引 > 发送事件序列长度
// 使用1:获取位置索引 = 2的 元素
// 位置索引从0开始
Observable.just(1, 2, 3, 4, 5)
.elementAt(2)
.subscribe(new Consumer<Integer>() {
@Override
public void accept( Integer integer) throws Exception {
Log.d(TAG,"获取到的事件元素是: "+ integer);
}
});
// 使用2:获取的位置索引 > 发送事件序列长度时,设置默认参数
Observable.just(1, 2, 3, 4, 5)
.elementAt(6 ,10) //默认值是10,位置6越界,则发送默认值10
.subscribe(new Consumer<Integer>() {
@Override
public void accept( Integer integer) throws Exception {
Log.d(TAG,"获取到的事件元素是: "+ integer);
}
});
3)elementAtOrError()
在elementAt()的基础上,当出现越界情况(即获取的位置索引 > 发送事件序列长度)时,即抛出异常
越界时,会抛出异常 NoSuchElementException
七、Rxjava背压相关理解
1、背景:观察者 & 被观察者 之间存在2种订阅关系:同步 & 异步。
1)同步订阅:观察者 & 被观察者 工作【在同一线程】
被观察者每次发送1个事件,必须等到观察者接收& 处理后,才能继续发送下一个事件
2)异步订阅:观察者 & 被观察者 工作【在不同线程】
被观察者 不需要 等待观察者接收& 处理后才能继续发送下一个事件,而是不断发送,直到发送事件完毕
但此时的事件并不会直接发送到观察者处,而是先发送到缓存区,等观察者从缓存区取出事件来处理。
被观察者发送事件速度 与 观察者接收事件速度 不匹配的情况。
i.发送 & 接收事件速度 = 单位时间内 发送 & 接收事件的数量
ii.多数情况,主要是 被观察者发送事件速度 > 观察者接收事件速度
问题:
被观察者 发送事件速度太快,而观察者 来不及接收所有事件,
从而导致观察者无法及时响应 / 处理所有发送过来事件的问题,
最终导致缓存区溢出、事件丢失 & OOM
解决方案:
采用背压策略。
2、背压策略
一种 控制事件流速 的策略,对超出缓存区大小的事件进行丢弃、保留、报错的措施。
在【异步订阅关系】中,控制事件发送 & 接收的速度
场景:被观察者发送事件速度 与 观察者接收事件速度 不匹配的场景;比如,网络请求。
3、背压策略的具体实现:Flowable
是RxJava 2.0中被观察者的一种新实现,同时也是背压策略实现的承载者
实现 非阻塞式背压 策略。
4、Flowable 特点
1)对应的观察者变为 Subscriber
2)所有的操作符强制支持背压
3)缓存区存放策略
i. 按发送顺序保存在缓存区,先发送、先进入缓存区
ii. 先进入缓存区的事件先取出
iii. 类似队列,实际上,在zip内部的实现 = 队列
4)默认的缓存区(队列)大小 = 128
5、Flowable的基础使用
//【步骤1】:创建被观察者 = Flowable
Flowable<Integer> upstream = Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
}, BackpressureStrategy.ERROR);
// 需要传入背压参数BackpressureStrategy,下面会详细讲解
//【步骤2】:创建观察者 = Subscriber
Subscriber<Integer> downstream = new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
/* 对比Observer传入的Disposable参数,Subscriber此处传入的参数 = Subscription
* 相同点:Subscription具备Disposable参数的作用,即Disposable.dispose()切断连接,
* 同样的调用Subscription.cancel()切断连接
*
* 不同点:Subscription增加了void request(long n)
*/
s.request(Long.MAX_VALUE);// 关于request()下面会继续详细说明
}
...
};
//【步骤3】:建立订阅关系
upstream.subscribe(downstream);
6、控制 观察者接收事件 的速度
1)异步订阅情况
响应式拉取:观察者根据自身实际情况按需接收事件。
实现方式:【Subscriber.Subscription.request()】
通过观察者中的 onSubscribe()的 Subscription 参数的 request()方法控制流速。
注意:
异步订阅情况,观察者没有设置 Subscription.request(long n),即说明观察者不接收事件。
此时被观察者仍能继续发送事件(存放在缓存区),等观察者需要时再取出被观察者事件。
缓存区溢出时,会报错 MissingResourceException。
// 1. 创建被观察者Flowable
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
// 一共发送4个事件
Log.d(TAG, "发送事件 1");
emitter.onNext(1);
Log.d(TAG, "发送事件 2");
emitter.onNext(2);
Log.d(TAG, "发送事件 3");
emitter.onNext(3);
Log.d(TAG, "发送事件 4");
emitter.onNext(4);
Log.d(TAG, "发送完成");
emitter.onComplete();
}
}, BackpressureStrategy.ERROR)
.subscribeOn(Schedulers.io()) // 设置被观察者在io线程中进行
.observeOn(AndroidSchedulers.mainThread()) // 设置观察者在主线程中进行
.subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
/* 对比Observer传入的Disposable参数,Subscriber此处传入的参数 = Subscription
* 相同点:Subscription参数具备Disposable参数的作用,即Disposable.dispose()切断连接, 同样的调用Subscription.cancel()切断连接
* 不同点:Subscription增加了void request(long n)
*/
/* 作用:决定观察者能够接收多少个事件
* 如设置了s.request(3),这就说明观察者能够接收3个事件(多出的事件存放在缓存区)
* 官方默认推荐使用Long.MAX_VALUE,即s.request(Long.MAX_VALUE);
*/
s.request(3);
}
...
});
2)同步订阅的情况
同步订阅并不会出现被观察者发送事件速度 > 观察者接收事件速度的情况。
可是,却会出现被观察者发送事件数量 > 观察者接收事件数量的问题。
i. 同步订阅没有缓存区
ii.被观察者在发送1个事件后,必须等待观察者接收后,才能继续发下1个事件
结论:
如果观察者没有设置 Subscription.request(long n)
此时被观察者发送第一个事件,就会抛出 MissingResourceException
7、控制 被观察者发送事件 的速度
反馈控制:被观察者 根据 观察者的接收事件能力,控制发送事件速度。
实现方式:FlowableEmitter.requested()
通过 被观察者中 FlowableEmitter 类的 requested() 方法控制流速。
1)FlowableEmitter类的requested()介绍
public interface FlowableEmitter<T> extends Emitter<T> {
// FlowableEmitter = 1个接口,继承自Emitter
// Emitter 接口方法包括:onNext(),onComplete() & onError
/* 作用:返回当前线程中request(a)中的a值
* 该 request(a) 则是措施1中讲解的方法,作用 = 设置
*/
long requested();
...
}
2)每个线程中的 requested()的返回值 = 该线程中的 request(a)的a值
3)反向控制 被观察者发送速度 原理
同步订阅关系:
i.被观察者 FlowableEmitter.requested()的返回值 = 观察者 Subscription.request(a)的参数值
ii.被观察者通过 FlowableEmitter.requested()的返回值,知道了观察者接收事件的能力,
从而根据该信息控制事件发送速度,达到观察者反向控制被观察者的效果。
异步订阅关系:
i.被观察者 FlowableEmitter.requested() 的返回值,等于
被观察者线程中 RxJava内部调用的request(n)的n值。(n=128、96、0)
从而每次发送128、96、或0个事件给观察者。
ii.观察者requested() 的返回值 = 观察者线程中 request(a)中的参数a值
iii.由于二者处于不同线程,被观察者 无法通过 FlowableEmitter.requested() 知道观察者接收事件的能力
只能通过RxJava 内部固定设置,从而反向控制被观察者的发送事件速度。
同步订阅控制 被观察者速度 实现:
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
// 调用emitter.requested()获取当前观察者需要接收的事件数量
long n = emitter.requested();
Log.d(TAG, "观察者可接收事件" + n);
// 根据emitter.requested()的值,即当前观察者需要接收的事件数量来发送事件
for (int i = 0; i < n; i++) {
Log.d(TAG, "发送了事件" + i);
emitter.onNext(i);
}
}
}, BackpressureStrategy.ERROR)
.subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, "onSubscribe");
// 设置观察者每次能接受10个事件
s.request(10);
}
...
});
特别注意 FlowableEmitter.requested():
[a]可叠加性 观察者可连续要求接收事件,被观察者会进行叠加并一起发送。
[b]实时更新性 每次发送事件后, FlowableEmitter.requested()的返回值会实时更新观察者能接收的事件。
仅计算Next事件,complete & error事件不算
[c]异常 FlowableEmitter.requested()返回值 = 0 时,代表观察者已经不可接收事件。
此时,被观察者继续发送事件,会抛出 MissingResourceException。
异步订阅控制 被观察者速度 实现:
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> emitter) throws Exception {
// 调用emitter.requested()获取当前观察者需要接收的事件数量
Log.d(TAG, "观察者可接收事件数量 = " + emitter.requested());
}
}, BackpressureStrategy.ERROR).subscribeOn(Schedulers.io()) //设置被观察者在io线程中进行
.observeOn(AndroidSchedulers.mainThread()) //设置观察者在主线程中进行
.subscribe(new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
/*
* 该设置仅影响 观察者线程中的requested,却不会影响的被观察者中的 FlowableEmitter.requested()的返回值
* 因为FlowableEmitter.requested()的返回值 取决于RxJava内部调用request(n),而该内部调用会在一开始就调用 request(128)
*/
s.request(150);
}
...
});
8、背压策略模式:BackpressureStrategy
当缓存区大小存满、被观察者仍然继续发送下1个事件时,该如何处理的策略方式
1)BackpressureStrategy.ERROR 直接抛出 MissingResourceException
2)BackpressureStrategy.MISSING 友好提示:缓冲区满了
3)BackpressureStrategy.BUFFER 将缓存区大小设置成无限大
4)BackpressureStrategy.DROP 超过缓存区大小(128) 的事件不再接收,丢弃
5)BackpressureStrategy.LATEST 只保存最新(最后事件),超过缓存区大小的事件丢弃
9、注意事项
FLowable 可通过自己创建(如上面例子),或通过其他方式自动创建,如 interval()操作符
1)对于自身手动创建FLowable的情况,可通过传入背压模式参数选择背压策略
2)可是对于自动创建FLowable,却无法手动传入传入背压模式参数,
那么出现流速不匹配的情况下,该如何选择 背压模式呢?
解决方案:
RxJava 2.0内部提供 封装了背压策略模式的方法,默认采用BackpressureStrategy.ERROR模式
onBackpressureBuffer()
onBackpressureDrop()
onBackpressureLatest()
Flowable.interval(1, TimeUnit.MILLISECONDS)
// 添加背压策略封装好的方法,此处选择Buffer模式,即缓存区大小无限制
.onBackpressureBuffer()
.observeOn(Schedulers.newThread())
.subscribe(new Subscriber<Long>() {
@Override
public void onSubscribe(Subscription s) {
Log.d(TAG, "onSubscribe");
mSubscription = s;
s.request(Long.MAX_VALUE);
}
...
});
推荐阅读:
Android Rxjava:这是一篇 清晰 & 易懂的Rxjava 入门教程 https://www.jianshu.com/p/a406b94f3188