Android 实现retryWhen逻辑

Android 实现retryWhen逻辑,android,session,retrofit,rx-java,Android,Session,Retrofit,Rx Java,我有一个需要会话(cookies)来处理网络呼叫的应用程序。Im使用改装+RxJava。不过,会话可能会过期(状态为401 Unauthorized的改装错误),我想重新验证(以获取新的cookie),并在这种情况下重试上一次调用。如何使用RxJava 我的例子是: getServerApi().getDialogs(offset, getCookies()) .subscribeOn(Schedulers.newThread()) .observeOn(AndroidSch

我有一个需要会话(cookies)来处理网络呼叫的应用程序。Im使用
改装+RxJava
。不过,会话可能会过期(状态为401 Unauthorized的改装错误),我想重新验证(以获取新的cookie),并在这种情况下重试上一次调用。如何使用
RxJava

我的例子是:

getServerApi().getDialogs(offset, getCookies())
     .subscribeOn(Schedulers.newThread())
     .observeOn(AndroidSchedulers.mainThread())
     .retryWhen(observable -> {...}) // Need some logic
     .subscribe(dialogsEnvelope -> getView().setDialogs(dialogsEnvelope),
                throwable -> getView().setError(processFail(throwable)));

虽然对于这个特定问题,
拦截器
可能是一个更好的解决方案,但这个问题特别要求使用
retryWhen
来解决,因此这里有一种方法:

retryWhen(new Func1<Observable<Throwable>, Observable<?>>(){

    @Override
    public void Observable<?> call(Observable<Throwable>> attempts) {
        return attempts.flatMap(new Func1<Throwable, Observable<?>>() {

            @Override
            public Observable<?> call(Throwable throwable) {
                 if (throwable instanceof RetrofitError) {
                     RetrofitError retrofitError = (RetrofitError) throwable;
                     if (retrofitError.getKind() == RetrofitError.Kind.HTTP && retrofitError.getResponse().getStatus() == 401) {
                         // this is the error we care about - to trigger a retry we need to emit anything other than onError or onCompleted
                         return Observable.just(new Object());
                     } else {
                         // some other kind of error: just pass it along and don't retry
                         return Observable.error(throwable);
                     }
                 } else {
                     // some other kind of error: just pass it along and don't retry
                     return Observable.error(throwable);
                 }
             }
        });
    }
})
retryWhen(新Func1调用(可观察>尝试){
返回尝试次数.flatMap(新Func1调用(Throwable Throwable){
if(可丢弃的实例错误){
RefundationError RefundationError=(RefundationError)可丢弃;
if(RefughtError.getKind()==RefughtError.Kind.HTTP&&RefughtError.getResponse().getStatus()==401){
//这是我们关心的错误-要触发重试,我们需要发出除onError或onCompleted之外的任何消息
返回Observable.just(newobject());
}否则{
//其他类型的错误:只需传递它,而不重试
返回可观测误差(可丢弃);
}
}否则{
//其他类型的错误:只需传递它,而不重试
返回可观测误差(可丢弃);
}
}
});
}
})

但是,如果进行简单的
重试
,则不会再次调用您的
getCookies
。这将只是重新订阅相同的
Observable
,但是在创建
Observable
之前调用了
getCookies
。因此,我认为您必须将源
可观察的
的创建封装在
延迟
中,使用OkHttp的强大功能


请记住同步您的身份验证过程代码,以便两个并发请求不会同时调用它。

在浏览Internet以查找正确答案时-我发现描述了如何在
OkHttp拦截器的帮助下刷新OAuth令牌(类似于已接受的答案,但更完整)


它与RxJava无关,但对我来说,它更容易接受,因为我不必用
retryWith
逻辑来包装每个可观察对象-所有事情都在较低的级别上完成(
OkHttp
library)。

如果会话过期,您需要重试,您是否会得到某种服务器响应来表明(例如,带有
“success”:false
)或者你只是一个
错误
?@david.mihola,更新了我的问题。我得到了401个未经授权的错误(获取RetroFit错误)。我想我有一个主意,但我想在发布之前尝试一下……谢谢,我会尝试的!在这个例子中,
重试
也可以……为你节省一张平面图。
public class RecoverInterceptor implements Interceptor {
  String getAuth() {
    // check if we have auth, if not, authorize
    return "Bearer ...";
  }

  void clearAuth() {
    // clear everything
  }

  @Override public Response intercept(Chain chain) throws IOException {
    final Request request = chain.request();
    if (request.urlString().startsWith("MY ENDPOINT")) {
      final Request signed = request.newBuilder()
          .header("Authorization", getAuth())
          .build();
      final Response response = chain.proceed(signed);
      if (response.code() == 401) {
        clearAuth();
        return intercept(chain);
      } else {
        return response;
      }
    } else {
      return chain.proceed(request);
    }
  }
}