我们在向后台请求数据的的时候,有时候可能会发现异常的情况,可能会要求你请求3次或者更多次,比如扫码登录的时候,我们可能会要求每隔几秒就需要去查询当前的扫码的状态,这也需以便确定是不是已经登录成功,要多次不断的去发送请求,多次求情的时候为了使代码更优雅的实现,我们可以利用rxjava的RetryWhen来实现。
RetryWhen这个操作符的作用是当观察者发送异常的时候,该方法会被调用,在这个方法中我们会根据我们的逻辑来判断是继续抛出这个异常,还是重新订阅观察者,这么说可能比较模糊,看下列子:
var count: Int = 0
Observable.create(ObservableOnSubscribe<String> { emitter ->
count ++
Log.i(TAG, "onCreate: 创造数字$count")
emitter?.onNext("$count")
}).flatMap {
if(it.toInt() < 100){
Observable.error(Exception())
}else{
Observable.just(it)
}
}.retryWhen {
it.flatMap {
throwable ->
if(throwable is Exception){
Observable.timer(2, TimeUnit.SECONDS)
}else{
Observable.error(throwable)
}
}
}
.subscribe({
Log.i(TAG, "subscribe: $it")
}, {
Log.i(TAG, "subscribe: $it")
})
}
这个会一直执行,直到count的值为100,之后抛出异常,执行subscribe,程序终止。
RetryWhen这个操作符的作用就是当接收到异常或者错误的时候将会执行RetryWhen这个操作符,这个操作符里面的返回的事件决定了是不是会重新订阅,如果返回的是onCompleted或者onError则不会重新订阅,如果返回的是onNext,则表示订阅该事件。
为了以后用起来简单,我们可以利用transform抽象出来一个通用的重试类:
import io.reactivex.*
import io.reactivex.functions.Function
import org.reactivestreams.Publisher
import java.util.concurrent.TimeUnit
class RetryWhenTransformer<T>(private var count: Int, private val time:Long) : ObservableTransformer<T, T>, FlowableTransformer<T, T>,
SingleTransformer<T, T>, MaybeTransformer<T, T> {
private fun retryObservableFunction(): Function<Observable<Throwable>, ObservableSource<Any>> {
return Function { t ->
t!!.flatMap { throwable ->
count--
if (count < 0) {
Observable.error(throwable)
} else {
Observable.timer(time.toLong(), TimeUnit.SECONDS)
}
}
}
}
private fun retryFlowableFunction(): Function<Flowable<Throwable>, Publisher<Any>> {
return Function {
it.flatMap { throwable ->
count--
if (count < 0) {
Flowable.timer(time, TimeUnit.SECONDS)
} else {
Flowable.error(throwable)
}
}
}
}
override fun apply(upstream: Observable<T>?): Observable<T>? {
return upstream?.retryWhen(retryObservableFunction())
}
override fun apply(upstream: Flowable<T>?): Flowable<T>? {
return upstream?.retryWhen(retryFlowableFunction())
}
override fun apply(upstream: Single<T>?): Single<T>? {
return upstream?.retryWhen(retryFlowableFunction())
}
override fun apply(upstream: Maybe<T>?): Maybe<T>? {
return upstream?.retryWhen(retryFlowableFunction())
}
重写这个类ObservableTransformer<T, T>, FlowableTransformer<T, T>,
SingleTransformer<T, T>, MaybeTransformer<T, T> 实现对应的apply方法就ok了。
调用的时候还需要传入次数和间隔时间即可:如果不确定次数的话可以穿一个极大值 比如 Int.MAX_VALUE
var count: Int = 0
Observable.create(ObservableOnSubscribe<String> { emitter ->
count ++
Log.i(TAG, "onCreate: 创造数字$count")
emitter?.onNext("$count")
})
.flatMap {
if(it.toInt() < 100){
Observable.error(Exception())
}else{
Observable.just(it)
}
}
.compose(RetryWhenTransformer(4, 2))
.subscribe({
Log.i(TAG, "subscribe: $it")
},
{
Log.i(TAG, "subscribe: $it")
})
}
}
结果如下:
I/MainActivity: onCreate: 创造数字1
I/MainActivity: onCreate: 创造数字2
I/MainActivity: onCreate: 创造数字3
I/MainActivity: onCreate: 创造数字4
I/MainActivity: onCreate: 创造数字5
I/MainActivity: subscribe: java.lang.NumberFormatException: For input string: "test-5"