Sim*_*uis 12 android retrofit okhttp retrofit2 okhttp3
我正在尝试使用OkHttp 3.12.0中最近添加的功能:全操作超时.为此,我还依赖于Invocation翻新2.5.0中的新类,它允许我检索方法注释.
注释是:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Timeout {
int value();
TimeUnit unit();
}
Run Code Online (Sandbox Code Playgroud)
改造界面是:
public interface AgentApi {
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
@GET("something")
Call<String> getSomething();
}
Run Code Online (Sandbox Code Playgroud)
拦截器是:
class TimeoutInterceptor implements Interceptor {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
final Invocation tag = request.tag(Invocation.class);
final Method method = tag != null ? tag.method() : null;
final Timeout timeout = method != null ? method.getAnnotation(Timeout.class) : null;
if (timeout != null) {
chain.call().timeout().timeout(timeout.value(), timeout.unit());
}
return chain.proceed(request);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经.addInterceptor(...)在提供给Retrofit Builder的OkHttpClient中正确添加了TimeoutInterceptor .
不幸的是,它没有像我预期的那样工作.达到超时后,呼叫不会失败?
虽然它在使用拦截器的链方法时工作正常:
chain
.withConnectTimeout(connect, unit)
.withReadTimeout(read, unit)
.withWriteTimeout(write, unit)
Run Code Online (Sandbox Code Playgroud)
这是因为必须在呼叫排队之前设置呼叫超时吗?(并且Interceptor在这个过程中被触发得太晚了?),还是这个呢?
不幸的是你是对的。这是因为OkHttpClient在执行拦截器链之前超时。如果您查看okhttp3.RealCallResponse execute()类中的方法,您会发现该行是安排超时的地方,并且在执行拦截器的地方之前调用它。timeout.enter()OkHttpgetResponseWithInterceptorChain()
幸运的是,您可以为此编写解决方法:) 将您的包放入包TimeoutInterceptor中okhttp3(您可以在应用程序中创建该包)。这将允许您访问RealCall具有包可见性的对象。你的TimeoutInterceptor类应该是这样的:
package okhttp3;
public class TimeoutInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Invocation tag = request.tag(Invocation.class);
Method method = tag != null ? tag.method() : null;
Timeout timeout = method != null ? method.getAnnotation(Timeout.class) : null;
if (timeout != null) {
chain.call().timeout().timeout(timeout.value(), timeout.unit());
RealCall realCall = (RealCall) chain.call();
realCall.timeout.enter();
}
return chain.proceed(request);
}
}
Run Code Online (Sandbox Code Playgroud)
解决方法是timeout.enter()在更改超时后再次执行。所有的魔法都发生在一行中:
RealCall realCall = (RealCall) chain.call();
realCall.timeout.enter();
Run Code Online (Sandbox Code Playgroud)
祝你好运!