什么是RxJava
RxJava 是一个在 Java 虚拟机(JVM)上使用的响应式编程扩展库。它基于观察者模式,用于处理异步和基于事件的程序。它有几个重要的组成部分:
- Observable(被观察者):可以发出一系列的数据或者事件,这些数据或事件可以是各种类型,比如整形、字符串、自定义对象等。例如,一个网络请求的响应数据就可以作为 Observable 发出的内容。
- Observer(观察者):用于接收和处理 Observable 发出的数据。当 Observable 有新的数据发出时,Observer 就会相应的进行处理,处理方式可以是简单地打印数据,也可以是复杂的业务逻辑操作,如把数据存储到数据库或者更新用户界面等。
- 各种操作符:它们能够对 Observable 发出的数据进行转换、过滤、组合等操作。比如,map 操作符可以将 Observable 发出的一种类型的数据转换为另一种数据。假设 Observable 发出的是一个代表学生成绩的整形数值,通过 map 操作符可以将其转换为代表优秀、良好、不及格的字符串描述。它们使数据处理更加灵活和方便。
在实际应用中,RxJava 被广泛应用于安卓开发和后端服务器开发等领域。在安卓开发中,它可以很好地处理各种异步操作,像网络请求、文件读取、传感器数据获取等。在后端开发中,对于处理高并发的异步事件流,如消息队列的消息处理等场合也非常有用。
RxJava 的主要特点
RxJava 具有异步性、强大的操作符功能,良好的链式调用风格、支持背压机制等特点。
- 异步性。它能够方便地处理异步操作,在很多场景下可以替代传统的异步编程方式。例如,在进行网络请求时,传统方式可能需要使用复杂的回调机制来处理请求成功或者失败的操作。而 RxJava 可以通过简单地创建 Observable 来表示网络请求操作,然后添加 Observer 来接收请求的结果。这种异步操作的处理方式使得程序可以在等待网络请求结果的同时,去执行其他任务,提高了程序的整体性能和响应速度。
- 强大的操作符功能。有大量的操作符可供使用,比如用于数据转换的 map 操作符、用于数据过滤的 filter 操作符、用于合并多个数据源的 merge 操作符等。以 map 操作符为例,假设有一个获取用户信息列表的 Observable,其中每个用户信息对象包含用户 ID 和年龄等属性。如果想要只获取用户年龄的列表,可以使用 map 操作符来提取每个用户信息中的年龄属性,形成一个新的只包含年龄的 Observable.
- 良好的链式调用风格。通过链式调用,可以将多个操作符和处理步骤连贯地组合在一起,使得代码更加清晰和易读。比如,在处理一个文件读取和数据解析的任务时,可以先通过一个 Observable 来表示文件读取操作,然后用 map 操作符来解析读取到的数据,再使用 filter 操作符来筛选出符合条件的数据,最后通过 subscribe 操作符来处理筛选后的数据,整个过程可以通过链式调用一气呵成地写出来。
- 支持背压(Backpressure)机制。在异步事件流中,当观察者处理事件的速度跟不上被观察者发送事件的速度时,背压机制就会发挥作用。它可以有效地控制事件的流速,避免观察者被大量的数据淹没而导致程序崩溃或者出现异常。例如,在一个从传感器不断获取数据的场景中,如果数据产生的速度很快,而处理数据的下游操作比较复杂,处理速度很慢,背压机制可以对数据进行缓冲或者丢弃等操作,以确保程序的稳定运行。
RxJava 的主要用途
在安卓开发中,RxJava 有大量的应用场景。
- 网络请求方面,它可以用来处理各种网络 API 的调用。例如,在获取新闻列表的应用中,使用 RxJava 可以方便地创建一个 Observable 来代表网络请求操作,当请求成功时,将返回的新闻数据传递给 Observer 进行处理,如将新闻标题和内容展示在列表视图中。同时,如果网络请求失败,也可以在 Observer 中统一处理错误情况,比如弹出提示框告知用户网络连接错误。
- 文件操作。比如在读取文件内容时,可以将文件读取操作封装为一个 Observable,通过操作符可以对读取到的文件内容进行处理。假设是读取一个配置文件,里面存储了应用的各种参数,使用 RxJava 可以方便地读取文件内容后,通过 map 操作符将内容解析为配置参数对象,再使用 filter 操作符筛选出需要的参数,然后传递给应用的其他模块进行使用。
- 安卓的用户界面(UI)更新方面,它能够很好地结合安卓的 UI 框架。由于安卓中不能在非 UI 线程直接更新 UI,RxJava 可以通过适当的操作符和调度器,确保数据的处理和 UI 的更新在合适的线程进行。例如,在一个实时更新股票价格的应用中,从网络获取股票价格数据的操作在后台线程进行,通过 RxJava 的调度器,可以将处理后的价格数据切换到 UI 线程,然后更新界面上显示股票价格的文本视图。
- 在后端开发中,RxJava 同样有诸多用途。对于处理消息队列中的消息,它可以将消息的接收和处理抽象为 Observable 和 Observer。例如,在一个电商系统的消息队列中,处理订单状态更新的消息。当有新的订单状态更新消息进入队列时,RxJava 可以将其作为 Observable 发出的事件,然后由 Observer 来处理这些消息,如更新数据库中的订单状态记录,发送通知给用户等。
- 大数据处理和实时数据处理。对于实时数据流,如服务器日志数据的实时分析,RxJava 可以对不断产生的日志数据进行处理。通过操作符可以过滤出关键的日志信息,对数据进行聚合等操作,以便快速发现系统的异常或者性能问题。
RxJava 的基本原理
RxJava 的核心基于观察者模式。在这个模式中,有 Observable(被观察者)和 Observer(观察者)两个主要角色。
Observable 负责产生数据或者事件。它可以是一个简单的数据源,如一个固定的整数数组,每次从数组中取出一个元素并发出;也可以是一个复杂的异步操作,比如网络请求。当 Observable 有新的数据或者事件产生时,它会通知与之关联的 Observer。
Observer 则负责接收和处理 Observable 发出的数据。它定义了一系列的回调方法,最主要的是 onNext、onError 和 onComplete。当 Observable 发出一个新的数据项时, Observer 的 onNext 方法会被调用,传递过来的数据就可以在这个方法中进行处理。例如,如果 Observable 发出的是用户的位置信息,onNext 方法就可以将这个位置信息更新到地图应用的界面上显示。
如果在 Observable 的生命周期内发生了错误,比如网络请求出现异常或者数据解析出错, Observable 会调用 Observer 的 onError 方法,在这个方法中,可以对错误进行统一的处理,如记录错误日志、弹出错误提示框等。
当 Observable 完成了所有数据的发送,它会调用 Observer 的 onComplete 方法,这个方法通常用于进行一些清理或者后续的操作,比如关闭网络连接、释放资源等。
RxJava 还通过操作符来构建复杂的数据处理管道。操作符本质上是对 Observable 进行转换的函数。例如,flatMap 操作符可以将一个 Observable 发出的每个数据项转换为一个新的 Observable,然后将这些新的 Observable 发出的数据合并成一个新的 Observable。假设有一个 Observable 发出的是用户 ID 列表,通过 flatMap 操作符可以为每个用户 ID 发起一个网络请求获取用户详细信息,然后将所有获取到的用户详细信息合并成一个新的 Observable。
另外,RxJava 的调度器(Scheduler)机制可以控制操作执行的线程。不同的操作可以在不同的线程中进行,比如网络请求操作可以在后台线程进行,而 UI 更新操作可以在主线程进行,调度器可以根据需要灵活地切换操作的执行线程,确保程序的性能和正确性。
RxJava 相比于传统异步编程方式的优势
RxJava 3 几个基类
RxJava 3 具有几个基类,您可以在其上发现运算符:
- io.reactivex.rxjava3.core.Flowable:0…N 个流,支持 Reactive-Streams 和背压
- io.reactivex.rxjava3.core.Observable: 0…N 流,无背压,
- io.reactivex.rxjava3.core.Single:恰好包含 1 个项目的流或错误,
- io.reactivex.rxjava3.core.Completable:一个没有项目但只有完成或错误信号的流,
- io.reactivex.rxjava3.core.Maybe:没有项、只有一个项或错误的流。
一、Flowable
Flowable是RxJava 2.0 版本为了“背压”推出的新类,提供背压策略,解决背压问题,使用方法大部分与Observable一样。
1、Flowable与Observable的区别
Flowable | Observable | |
---|---|---|
被观察者 | FlowableOnSubscribe | ObservableOnSubscribe |
观察者 | Subscriber | Observer |
create() | create(FlowableOnSubscribe, BackpressureStrategy) | create(ObservableOnSubscribe) |
背压操作符 | onBackpressureDrop() onBackpressureBuffer() onBackpressureLaster() |
两者除了以上显示的区别,其他使用都是完全一样的。
2、BackpressureStrategy类型
Flowable的create中包含BackpressureStrategy类,其中包含5个类型:
- BackpressureStrategy.ERROR: 当被观察者发送事件数量大于128时, 观察者抛出异常并终止接收事件,但不影响被观察者继续发送事件。
- BackpressureStrategy.BUFFER:与Observable一样存在背压问题,但是接收性能比Observable低,因为BUFFER类型通过BufferAsyncEmitter添加了额外的逻辑处理,再发送至观察者。
- BackpressureStrategy.DROP:每当观察者接收128个事件后,就会丢弃部分事件。
- BackpressureStrategy.LATEST:LATEST与DROP效果一样,但LATEST会保证能接收最后一个事件,而DROP则不会保证。
- BackpressureStrategy.MISSING:没有采取背压策略的类型,效果跟Observable一样。设置该类型时,可以配合onBackPressure相关操作符使用,可以达到上述其他类型的效果。
3、onBackPressure背压操作符
- onBackpressureDrop():与BackpressureStrategy.DROP一样效果。
- onBackpressureBuffer():与BackpressureStrategy.BUFFER一样效果。
- onBackpressureLatest():与BackpressureStrategy.LATEST一样效果。
4、request(count: Int) 设置接收事件的数量
在Subscriber接口的onSubscribe函数中,需要调用Subscription的request函数,设置接收事件的数量,否则将接收不到事件。
class HelloSubscriber<T> : Subscriber<T> {
override fun onSubscribe(s: Subscription?) {
// 观察者设置接收事件的数量,否则接收不到事件
s?.request(Long.MAX_VALUE)
println("onSubscribe")
}
override fun onNext(t: T) {
println("onNext: $t")
}
override fun onError(t: Throwable?) {
println("onError")
}
override fun onComplete() {
println("onComplete")
}
}
5、简单实例
fun <T: Any> flowableCreate(item: T) : Flowable<T> {
return Flowable.create({ emitter ->
println(" flowable subscribe")
emitter.onNext(item)
println("onNext send $item")
Thread.sleep(50)
}, BackpressureStrategy.BUFFER)
}
fun flowableDemo() {
// 发送一个事件就结束
val subscriber = HelloSubscriber<String>()
Flowable.just("flowable just subscriber").subscribe(subscriber)
flowableCreate("test flowable")
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.newThread())
.subscribe(subscriber)
}