简单介绍
RxJava是基于 JVM的对ReactiveX(又称响应式编程)的一种实现。因为是基于JVM的,所以不仅是java语言环境可以使用RxJava,所有基于JVM的语言(比如:Kotlin,Scala,Groovy等)也可以使用RxJava.
RxJava的特点:异步 流式(链式)调用
核心思想(流水线)
起点----终点
就像工厂车间流水线一样,一个起点(Observable),一个终点(Observer),在起点和终点之间可以进行各种加工操作(操作符),下线的人只关心相邻上线提供的半成品,而不关心其它工位提供的半成品是什么。
引入
compile ‘io.reactivex.rxjava3:rxjava:3.0.4’
查看最新版本
简单使用
使用的时候只需要关心两个角色,一个被观察者(Observable),一个观察者(Observer)。
Observable创建操作符
Observable的创建,库提供了很多方法和操作符,这里只介绍几个常用的,大家参考文档举一反三。
create
最基本,但不常用,使用提供的操作符基本能满足需求
val observable = Observable.create(object : ObservableOnSubscribe<String> {
override fun subscribe(emitter: ObservableEmitter<String>) {
emitter.onNext("ayy")
emitter.onComplete()
}
})
interval
周期执行,如下:每隔1秒执行一次,无限循环,不会终止。
Observable.interval(1, TimeUnit.SECONDS)
.subscribe {
Log.e(TAG, "间隔执行:$it ")
}
intervalRange
与interval相比,周期执行有限的次数。这种可以应用到获取验证码的倒计时场景中。
//倒计时,比如发送短信验证码倒计时 0-59
Observable.intervalRange(0, 61, 0, 1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ Log.e(TAG, "accept: 倒计时${60 - it}") },
{ Log.e(TAG, "accept: onError") },
{ Log.e(TAG, "run: 完成,再次发送验证码") })
timer
计时器,多少秒后执行
//计时器,5秒后执行
Observable.timer(5, TimeUnit.SECONDS).subscribe {
Log.e(TAG, "click: $it")
}
Observer
val observer = object :Observer<String>{
override fun onComplete() {
Log.e(TAG, "onComplete: 完成时调用" )
}
override fun onSubscribe(d: Disposable?) {
Log.e(TAG, "onSubscribe: 订阅时调用" )
}
override fun onNext(t: String?) {
Log.e(TAG, "onNext: " )
}
override fun onError(e: Throwable?) {
Log.e(TAG, "onError: onError后,后续的事件不会再发出" )
}
}
当然还有更简单的,使用Consumer,结合Java8或者kotlin的lambda代码更简洁:
1.只关心onNext方法
Observable.just("")
.subscribe(object : Consumer<String> {
override fun accept(t: String?) {
Log.e(TAG, "accept: 相当于onNext" )
}
})
使用lambda简化:
Observable.just("")
.subscribe { Log.e(TAG, "accept: 相当于onNext" ) }
2.只关心onNext和onError方法
Observable.just("")
.subscribe(object :Consumer<String>{
override fun accept(t: String?) {
Log.e(TAG, "accept: 相当于onNext" )
}
},object :Consumer<Throwable>{
override fun accept(t: Throwable?) {
Log.e(TAG, "accept: 相当于onError" )
}
})
使用lambda简化后:
Observable.just("")
.subscribe(
{ Log.e(TAG, "accept: 相当于onNext") },
{ Log.e(TAG, "accept: 相当于onError") })
3.onNext,onError,onComplete都关心
Observable.just("")
.subscribe(object :Consumer<String>{
override fun accept(t: String?) {
Log.e(TAG, "accept: 相当于onNext" )
}
},object :Consumer<Throwable>{
override fun accept(t: Throwable?) {
Log.e(TAG, "accept: 相当于onError" )
}
},object :Action{
override fun run() {
Log.e(TAG, "run: 相当于onComplete方法" )
}
})
简化后:
Observable.just("")
.subscribe(
{ Log.e(TAG, "accept: 相当于onNext") },
{ Log.e(TAG, "accept: 相当于onError") },
{ Log.e(TAG, "run: 相当于onComplete方法") })
线程调度
线程调度不好用文字表达清楚,记住结论即可:
subscribeOn决定上面的代码所在线程;
observeOn决定下面代码所在线程。
其中io线程的调度内部使用了线程池,main线程的调度使用了handler来将代码切换到主线程中执行。
网络嵌套(串行)
场景:一键登录,以手机号为参数,先请求接口拿到认证token,再以token为参数请求用户信息。使用flatMap操作符。
HttpUtil.api.getToken("手机号")
.subscribeOn(Schedulers.io())
.flatMap { token ->
HttpUtil.api.getUserInfo(token)
}.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Log.e(TAG, "click: 请求到用户信息")
}, {
it.printStackTrace()
Log.e(TAG, "click: 异常:${it.message}")
})
场景:先操作本地数据库查询缓存数据,再请求网络更新UI,数据库操作在非UI线程中执行
Observable.create<List<User>> {
//模拟查询数据库
Thread.sleep(1000)
val data = mutableListOf<User>()
for (i in 0..10) {
data.add(User())
}
it.onNext(data)
// it.onComplete()
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap {
//更新UI,展示缓存数据
Log.e(TAG, "click: $it")
HttpUtil.api.getUserList()
}.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
//更新UI,替换缓存数据,展示网络数据
Log.e(TAG, "click: ${it.data}")
}