应用场景
这里使用平时开发过程中经常遇到的一个场景作为例子讲解,网络请求失败重试,当在业务层面,比如登录超或者token失效,需要重新获取token才能发起当前请求时,我们就可以使用retry完成该需求,这里其实涉及请求的嵌套。
代码分析
首先别忘了添加rxjava相关依赖,这里使用的是Rxjava1.0:
dependencies {
implementation 'io.reactivex:rxjava:1.3.0'
implementation 'io.reactivex:rxandroid:1.2.1'
}
这里是一个获取网络图片列表的例子:
private void fetchPhotoList() {
Observable.unsafeCreate(new Observable.OnSubscribe<List<Photo>>() {
@Override
public void call(Subscriber<? super List<Photo>> subscriber) {
TokenHandler tokenHandler = TokenHandler.getInstance();
String token = tokenHandler.token(TokenHandler.FLAG_TOKEN_CACHE);// 请求时需要带上token
......
......
try {
......
......
JSONObject response = new JSONObject(buffer.toString());
if (checkToken(response)) {// 检查请求返回,是否发生token失效情况
List<Photo> photos = updateTinnoPhoto(response);
subscriber.onNext(photos);
subscriber.onCompleted();
} else {// token失效
tokenHandler.token(TokenHandler.FLAG_TOKEN_RESET); // 此处重新请求了token,当然也可以在重新请求前做这个处理
//抛出TinnoTokenException自定义异常
subscriber.onError(new TokenException(TokenException.TOKEN_EXP, "token is invalid"));
}
} catch (JSONException e) {
subscriber.onError(e);
} catch (Exception e) {
subscriber.onError(e);
}
}
})
.retryWhen(new RetryWithDelay(1, 3000)) // onError发生时,retryWhen操作符会触发处理,这里的1表示最大重试次数,3000表示延时请求时间
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Photo>>() {
@Override
public void onCompleted() {
startDownload();
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(List<Photo> photos) {
}
});
}
下面看下RetryWithDelay的实现,它实现一个Func1函数,作为发生请求失败时的回调接口:
public class RetryWithDelay implements
Func1<Observable<? extends Throwable>, Observable<?>> {
private final int maxRetries;
private final int retryDelayMillis;
private int retryCount;
public RetryWithDelay(int maxRetries, int retryDelayMillis) {
this.maxRetries = maxRetries;
this.retryDelayMillis = retryDelayMillis;
}
@Override
public Observable<?> call(Observable<? extends Throwable> attempts) {
return attempts
.flatMap(new Func1<Throwable, Observable<?>>() {
@Override
public Observable<?> call(Throwable throwable) {
if (++retryCount <= maxRetries && throwable instanceof TokenException) {// 所有的onError都会走到这里,根据需要添加判断控制
// When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
return Observable.timer(retryDelayMillis,
TimeUnit.MILLISECONDS);
}
// Max retries hit. Just pass the error along.
return Observable.error(throwable);
}
});
}
}
自定义异常:
public class TokenException extends RuntimeException {
public static final int TOKEN_EXP = 1;
private int errorCode;
public TokenException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
}