OkHttp Время ожидания вызова от Retrofit Interceptor с использованием аннотаций не применяется - PullRequest
0 голосов
/ 21 ноября 2018

Я пытаюсь использовать недавно добавленную функцию из OkHttp 3.12.0: тайм-ауты для полной операции.Для этого я также полагаюсь на новый класс Invocation из модификации 2.5.0, который позволяет мне извлекать аннотации методов.

Аннотация:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Timeout {

    int value();

    TimeUnit unit();

}

Интерфейс модернизации:

public interface AgentApi {

    @Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
    @GET("something")
    Call<String> getSomething();

}

И перехватчик:

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);
    }

}

Я правильно добавил TimeoutInterceptor с .addInterceptor(...) в OkHttpClient, предоставленном для Retrofit Builder.

К сожалению, это не работает, как я ожидал.Вызовы не прерываются при достижении времени ожидания?

Хотя он работает нормально при использовании цепных методов от перехватчика:

chain
  .withConnectTimeout(connect, unit)
  .withReadTimeout(read, unit)
  .withWriteTimeout(write, unit)

Это потому, что время ожидания вызова должно быть установлено довызов поставлен в очередь?(и перехватчик срабатывает слишком поздно в процессе?), или это что-то еще?

1 Ответ

0 голосов
/ 13 февраля 2019

К сожалению, вы правы.Это потому, что OkHttpClient получает тайм-ауты, прежде чем он выполняет цепочку перехватчиков.Если вы посмотрите на метод Response execute() в классе okhttp3.RealCall , вы найдете строку timeout.enter(), в которой OkHttp планирует тайм-ауты, и она вызывается до getResponseWithInterceptorChain(), то есть места, где выполняются перехватчики.

К счастью, вы можете написать обходной путь для этого :) Поместите свой 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);
   }
}

Обходной путь заключается в повторном выполнении timeout.enter() после изменения времени ожидания.Вся магия происходит в строках:

RealCall realCall = (RealCall) chain.call();
realCall.timeout.enter();

Удачи!

...