Programação de rede Android (12) Análise do princípio Retrofit2

1 Revisão de uso

Já introduzimos o uso do Retrofit na postagem anterior do blog "Uso do Retrofit2 Framework para Android Network Programming (11)" . Hoje continuamos a ler o código fonte do Retrofit para que ele possa ter um entendimento mais profundo. Antes de começarmos, vamos revisar o uso simples e seguir as etapas para analisar os princípios por trás de cada linha de código em profundidade, como:

    // 0 创建一个网络请求的接口
    public interface AppInfoService {
        @GET("url.json")
        Call<List<AppInfo>> getAppInfoList(@Query("id") int id);
    }

    private void getRequest() {
        // 1 创建 Retrofit 对象,输入请求URL、转换器等
        Retrofit retorfit = new Retrofit.Builder()
                .baseUrl("https://api.xx.com/ ")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        // 2 通过Retrofit的create创建自定义的请求接口对象
        AppInfoService appInfoService = retorfit.create(AppInfoService.class);
        // 3 通过调用请求接口方法创建Call对象
        Call<List<AppInfo>> call = appInfoService.getAppInfoList(123);
        // 4 发起同步或异步的网络请求
//        try {
//            Response<List<AppInfo>> response = call.execute();
//            List<AppInfo> appInfos = response.body();
//            Log.e("zyx", appInfos.toString());
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        call.enqueue(new Callback<List<AppInfo>>() {
            @Override
            public void onResponse(Call<List<AppInfo>> call, Response<List<AppInfo>> response) {
                List<AppInfo> appInfos = response.body();
                Log.e("zyx", appInfos.toString());
            }

            @Override
            public void onFailure(Call<List<AppInfo>> call, Throwable t) {
                Log.e("zyx", t.toString());
            }
        });
    }

Pode-se ver que as etapas são provavelmente:

0 Crie uma interface de solicitação de rede personalizada, que contenha o método de entrada de pedido, nome da interface do servidor de solicitação e parâmetros de solicitação;

1 Crie um objeto Retrofit, insira o URL da solicitação, o conversor etc.;

2 Crie um objeto de interface de solicitação personalizado através da criação de Retrofit;

3 Crie um objeto de chamada chamando o método da interface de solicitação;

4 Inicie solicitações de rede síncronas ou assíncronas.

2 Análise de princípios

2.1 Criar objeto Retrofit

O processo de criação de objetos Retrofit também é inicializado usando o padrão do construtor. Primeiro, o método Builder eventualmente chamará o método findPlatform da classe Platform.

Retrofit.java

public static final class Builder {
  // ……
  Builder(Platform platform) {
    this.platform = platform;
  }

  public Builder() {
    this(Platform.get());
  }
}

Platform.java

class Platform {
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
}

Como pode ser visto no código acima, o método findPlatform criará diferentes objetos Platform de acordo com diferentes plataformas operacionais. Em seguida, chame seu método de construção.

Retrofit.java

public final class Retrofit {
public static final class Builder {
    private final Platform platform;
    private @Nullable okhttp3.Call.Factory callFactory;
    private @Nullable HttpUrl baseUrl;
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
    private @Nullable Executor callbackExecutor;
    private boolean validateEagerly;

    // ……

    public Retrofit build() {
// 关键代码1,判断baseUrl是否为空
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }
      // 关键代码2,获得或创建 网络请求执行器工厂 okhttp3.Call.Factory对象
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      // 关键代码3,获得或创建回调方法执行器Executor对象
      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

// 关键代码4,创建 网络请求适配器工厂CallAdapter.Factory列表,
// 并将callAdapterFactories和上面的callbackExecutor对象创建出默认的defaultCallAdapterFactories添加其中
      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
      callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));

// 关键代码5,创建 数据转换器工厂Converter.Factory列表
      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size() + latform.defaultConverterFactoriesSize());
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
      converterFactories.addAll(this.converterFactories);
      converterFactories.addAll(platform.defaultConverterFactories());
      // 关键代码6,实例化Retrofit对象
      return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
          unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
    }
  }
}

A lógica no método Build é muito clara, principalmente 5 coisas:

  1. Para determinar se baseurl está vazio, o valor de baseurl é definido pelo método .baseUrl .
  2. A obtenção da rede um pedido para executar valor objeto de fábrica callFactory, se ela estiver vazia, então o objeto é criar um OkHttpClient, então obviamente Retrofit OkHttp solicitação de rede padrão, callFactory valores por . Cliente método é fornecido.
  3. Obtenha o valor do objeto callbackExecutor do executor do método de retorno de chamada.Se estiver vazio, crie um padrão.O padrão é um objeto MainThreadExecutor e possui um Handler com Looper dentro. O valor de callbackExecutor pode ser definido pelo método callbackExecutor .
  4. Obtenha o valor da callAdapterFactories de fábrica do adaptador de solicitação de rede e inclua-o na lista.O valor de callAdapterFactories pode ser configurado pelo método .addCallAdapterFactory . Após a criação da lista, adicione o objeto callbackExecutor no código de chave 3 a ele.
  5. Criar uma lista de plantas Converter.Factory conversor de dados, após a adição de built-in conversores de dados e BuiltInConverters defaultConverterFactories conversor de dados de fábrica, que também terá a converterFactories valor serão adicionados à lista, o valor pode ser obtido por converterFactories. AddConverterFactory Método para adicionar.
  6. Por fim, passe o objeto acima para o construtor Retrofit para instanciar o objeto Retrofit Observe que o valor validateEagerly significa que ele é verificado com antecedência, que pode ser definido pelo método .validateEagerly.

2.2 Crie um objeto de interface de solicitação personalizado através da criação de Retrofit

Por exemplo, o código AppInfoService appInfoService = retorfit.create (AppInfoService.class);, o método create do Retrofit é um método genérico, o parâmetro é um tipo de interface personalizado, o valor de retorno é um objeto de proxy dinâmico Proxy.newProxyInstance, consulte o código .

Retrofit.java

public final class Retrofit {
  // ……
  @SuppressWarnings("unchecked") // Single-interface proxy creation guarded by parameter safety.
  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
// 关键代码1,是否提前验证
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
// 关键代码2,创建一个用于网络请求接口的动态代理对象并返回 
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
// 关键代码3,加载网络请求接口里的方法,并执行
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
        loadServiceMethod(method);
      }
    }
  }
  // ……
}
  1. O método create determinará primeiro se a variável validateEagerly é verdadeira, ou seja, se é validada antecipadamente.O método eagerlyValidateMethods é na verdade para acionar a lógica do método loadServiceMethod no código da chave 3 antecipadamente.
  2. No código-chave 2, crie um objeto de proxy dinâmico para a interface de solicitação de rede, ou seja, quando chamarmos o método getAppInfoList usando AppInfoService no exemplo de retorno de chamada, o método de chamada do InvocationHandler será chamado.
  3. O código da chave 3 é carregar e executar o método na interface da solicitação de rede, o método getAppInfoList personalizado.

2.3 Crie um objeto de chamada chamando o método da interface de solicitação

O chamado código de exemplo <;, o processo retorna List <AppInfo >> chamada = appInfoService.getAppInfoList ( 123) um objeto de chamadas, o método conhecido de 2,2 a eventualmente chama Retrofit de loadServiceMethod método retorna do objeto de invocação de método para , Portanto, continuamos analisando o código do método loadServiceMethod e invocando o método.

2.3.1 loadServiceMethod 方法

Retrofit.java

public final class Retrofit {
  private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
  // ……
ServiceMethod<?> loadServiceMethod(Method method) {
    ServiceMethod<?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
// 关键代码
        result = ServiceMethod.parseAnnotations(this, method);
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }
// ……
}

O método loadServiceMethod primeiro lê o objeto estático Map serviceMethodCache se existe uma instância de solicitação de rede criada anteriormente e, se houver, ela retorna diretamente. Caso contrário, ele será criado pelo método ServiceMethod.parseAnnotations e, em seguida, adicionado ao serviceMethodCache para finalmente retornar o objeto recém-criado.

ServiceMethod.java

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 关键代码1,创建一个请求工厂RequestFactory对象
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);

    Type returnType = method.getGenericReturnType();
    if (Utils.hasUnresolvableType(returnType)) {
      throw methodError(method,
          "Method return type must not include a type variable or wildcard: %s", returnType);
    }
    if (returnType == void.class) {
      throw methodError(method, "Service methods cannot return void.");
    }

// 关键代码2,创建HttpServiceMethod对象并返回
    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

O método é fazer duas coisas:

  1. Crie uma fábrica de solicitações por meio do método parseAnnotations da classe RequestFactory.
  2. Por fim, crie um objeto HttpServiceMethod e retorne.

Abaixo, continuamos a analisar a lógica do método parseAnnotations de RequestFactory e do método parseAnnotations de HttpServiceMethod.

2.3.1.1 O método parseAnnotations de RequestFactory

RequestFactory.java

final class RequestFactory {
  static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
    return new Builder(retrofit, method).build();
  }

  private final Method method;
  private final HttpUrl baseUrl;
  final String httpMethod;
  private final @Nullable String relativeUrl;
  private final @Nullable Headers headers;
  private final @Nullable MediaType contentType;
  private final boolean hasBody;
  private final boolean isFormEncoded;
  private final boolean isMultipart;
  private final ParameterHandler<?>[] parameterHandlers;
  final boolean isKotlinSuspendFunction;

  RequestFactory(Builder builder) {
    method = builder.method;
    baseUrl = builder.retrofit.baseUrl;
    httpMethod = builder.httpMethod;
    relativeUrl = builder.relativeUrl;
    headers = builder.headers;
    contentType = builder.contentType;
    hasBody = builder.hasBody;
    isFormEncoded = builder.isFormEncoded;
    isMultipart = builder.isMultipart;
    parameterHandlers = builder.parameterHandlers;
    isKotlinSuspendFunction = builder.isKotlinSuspendFunction;
  }
// ……
  static final class Builder {
    // ……
    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

    RequestFactory build() {
      // ……
      return new RequestFactory(this);
    }
private void parseMethodAnnotation(Annotation annotation) {
    if (annotation instanceof DELETE) {
      parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
    } else if (annotation instanceof GET) {
      parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    } else if (annotation instanceof HEAD) {
      parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
    } else if (annotation instanceof PATCH) {
      parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
    } else if (annotation instanceof POST) {
      parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
    } else if (annotation instanceof PUT) {
      parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
    } else if (annotation instanceof OPTIONS) {
      parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
    } else if (annotation instanceof HTTP) {
      HTTP http = (HTTP) annotation;
      parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
    } else if (annotation instanceof retrofit2.http.Headers) {
      String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
      if (headersToParse.length == 0) {
        throw methodError(method, "@Headers annotation is empty.");
      }
      headers = parseHeaders(headersToParse);
    } else if (annotation instanceof Multipart) {
      if (isFormEncoded) {
        throw methodError(method, "Only one encoding annotation is allowed.");
      }
      isMultipart = true;
    } else if (annotation instanceof FormUrlEncoded) {
      if (isMultipart) {
        throw methodError(method, "Only one encoding annotation is allowed.");
      }
      isFormEncoded = true;
    }
  }
// ……
}

Pode-se observar que o método parseAnnotations de RequestFactory é realmente transmitido nos objetos Retrofit e nos parâmetros do método e, lendo os valores da anotação definidos no método (método parseMethodAnnotation na classe), é obtido um objeto de vários parâmetros de solicitação de rede.

2.3.1.2 O método parseAnnotations de HttpServiceMethod

Depois de obter o objeto RequestFactory, ele é passado para o método parseAnnotations de HttpServiceMethod como parâmetro e, em seguida, observe o código.

HttpServiceMethod.java

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
  static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
      Retrofit retrofit, Method method, RequestFactory requestFactory) {
    // ……
// 关键代码1,从Retrofit对象中的 网络请求适配器工厂 获得 网络请求适配器callAdapter和其请求类型
    CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, adapterType, annotations);
    Type responseType = callAdapter.responseType();
    if (responseType == okhttp3.Response.class) {
      throw methodError(method, "'" + getRawType(responseType).getName()
          + "' is not a valid response body type. Did you mean ResponseBody?");
    }
    if (responseType == Response.class) {
      throw methodError(method, "Response must include generic type (e.g., Response<String>)");
    }
    // TODO support Unit for Kotlin?
    if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
      throw methodError(method, "HEAD method must use Void as response type.");
    }

// 关键代码2,从Retrofit对象中的 数据转换器工厂 获得 数据转换器 responseConverter
    Converter<ResponseBody, ResponseT> responseConverter =  createResponseConverter(retrofit, method, responseType);

// 关键代码3,从Retrofit对象中的 获得 网络请求执行器工厂 callFactory
    okhttp3.Call.Factory callFactory = retrofit.callFactory;

// 关键代码4,根据类型创建不同的HttpServiceMethod实现
    if (!isKotlinSuspendFunction) {
      return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
    } else if (continuationWantsResponse) {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
    } else {
      //noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
      return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
          callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
          continuationBodyNullable);
    }
  }
  // ……
}

O método parseAnnotations de HttpServiceMethod obterá o adaptador de solicitação de rede callAdapter, o conversor de dados responseConverter, o executor de solicitação de rede factory callFactory e o request factory RequestFactory transmitidos nos parâmetros no objeto Retrofit como parâmetros para criar três tipos de É o objeto HttpServiceMethod de CallAdapted, SuspendForResponse e SuspendForBody. Entre eles, SuspendForResponse e SuspendForBody são suportados pelo método de suspensão Kotlin; portanto, apenas analisamos CallAdapted.

HttpServiceMethod.java

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  private final CallAdapter<ResponseT, ReturnT> callAdapter;

  CallAdapted(RequestFactory requestFactory, okhttp3.Call.Factory callFactory,
      Converter<ResponseBody, ResponseT> responseConverter,
      CallAdapter<ResponseT, ReturnT> callAdapter) {
    super(requestFactory, callFactory, responseConverter);
    this.callAdapter = callAdapter;
  }

  @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

 2.3.2 invocar método

Olhando para o retorno acima, loadServiceMethod (método) .invoke (args! = Null? Args: emptyArgs); código, quando o método loadServiceMethod retorna o objeto ServiceMethod, o método invoke é chamado.

ServiceMethod.java

abstract class ServiceMethod<T> {
  // ……
  abstract @Nullable T invoke(Object[] args);
}

A implementação do método invoke está na classe HttpServiceMethod.

HttpServiceMethod.java

abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
// ……
@Override final @Nullable ReturnT invoke(Object[] args) {
    Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
    return adapt(call, args);
  }
  protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
}

O método Invoke é muito simples, que é chamar o método adap, que é o método adap na classe de implementação CallAdapted of HttpServiceMethod. O código foi publicado acima. Lembre-se aqui que a primeira chamada de parâmetro é OkHttpCall.

HttpServiceMethod.java

static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {
  //……
  @Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
    return callAdapter.adapt(call);
  }
}

O melhor é o método de adaptação do adaptador de solicitação de rede callAdapter.

Esse adaptador de solicitação de rede callAdapter é o adaptador de solicitação de rede callAdapter obtido da fábrica do adaptador de solicitação de rede no objeto Retrofit no código de chave 1 no método parseAnnotations do HttpServiceMethod. Revendo a fábrica do adaptador de solicitação de rede criada no objeto Retrofit acima, foi mencionado que o valor da chamada de fábrica do adaptador de solicitação de rede pode ser definido pelo método .addCallAdapterFactory e pelo padrão defaultCallAdapterFactories

Platform.java

List<? extends CallAdapter.Factory> defaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
  return singletonList(new DefaultCallAdapterFactory(callbackExecutor));
}
DefaultCallAdapterFactory.java
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  private final @Nullable Executor callbackExecutor;

  DefaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    this.callbackExecutor = callbackExecutor;
  }

  @Override public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    if (!(returnType instanceof ParameterizedType)) {
      throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
    }
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }
}

Por fim, se não especificarmos o callAdapter por meio do método .addCallAdapterFactory, o método invoke será executado na classe DefaultCallAdapterFactory, portanto, o objeto Call criado será o objeto ExecutorCallbackCall.

O construtor ExecutorCallbackCall de DefaultCallAdapterFactory recebe dois parâmetros. Deixe-me falar sobre a segunda chamada de parâmetro, podemos saber que é um objeto OkHttpCall na chamada HttpServiceMethod. O primeiro parâmetro executor é o executor do método de retorno de chamada callbackExecutor quando o objeto Retrofit é criado.Se não for definido pelo método .callbackExecutor no momento, o padrão é platform.defaultCallbackExecutor (); um objeto MainThreadExecutor e seu código-fonte é o seguinte. Há um manipulador com Looper dentro.

Platform.java

class Platform {
  // ……
  static class Android extends Platform {
    // ……
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }
// ……
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}

2.4 Iniciando uma solicitação de rede

Depois de obter o objeto Chamada, é o último a enviar uma solicitação de rede. Pelo exposto, sabemos que o objeto Call é DefaultCallAdapterFactory.ExecutorCallbackCall, portanto, se é uma solicitação assíncrona ou síncrona, os métodos de enfileiramento e execução no DefaultCallAdapterFactory.ExecutorCallbackCall são chamados. O código fonte é o seguinte.

DefaultCallAdapterFactory.java

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  // ……
  static final class ExecutorCallbackCall<T> implements Call<T> {
    final Executor callbackExecutor;
    final Call<T> delegate;

    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              if (delegate.isCanceled()) {
                // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
                callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
              } else {
                callback.onResponse(ExecutorCallbackCall.this, response);
              }
            }
          });
        }

        @Override public void onFailure(Call<T> call, final Throwable t) {
          callbackExecutor.execute(new Runnable() {
            @Override public void run() {
              callback.onFailure(ExecutorCallbackCall.this, t);
            }
          });
        }
      });
    }

@Override public Response<T> execute() throws IOException {
      return delegate.execute();
    }
// ……
}

Os métodos de enfileirar e executar delegam ao objeto delegado para execução e o objeto delegado é o objeto OkHttpCall. Portanto, entendemos apenas a lógica de enfileiramento do OkHttpCall.

OkHttpCall.java

final class OkHttpCall<T> implements Call<T> {
  // ……
  @Override public void enqueue(final Callback<T> callback) {
    // ……
    okhttp3.Call call;
    // ……
      if (call == null && failure == null) {
        try {
// 关键代码1,创建okhttp3的call对象
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          // ……
        }
      }
    }
    // ……
// 关键代码2,执行call对象的异常请求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
        Response<T> response;
        try {
// 关键代码3,获得请求结果进行解析
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          throwIfFatal(e);
          callFailure(e);
          return;
        }

        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          throwIfFatal(t);
          t.printStackTrace(); // TODO this is not great
        }
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        callFailure(e);
      }
      // ……
    });
  }
  private okhttp3.Call createRawCall() throws IOException {
    okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
}

No código de chave 1, um objeto de chamada okhttp3 é criado pelo método createRawCall e, em seguida, a solicitação anormal de okhttp3 é executada no código de chave 2 e, em seguida, o resultado da solicitação é analisado e encapsulado no código de chave 3 pelo método parseResponse. O resultado final é chamado novamente em ExecutorCallbackCall e sabemos que o retorno de chamada de okhttp3 é executado no thread filho.No ExecutorCallbackCall é o objeto MainThreadExecutor, porque possui um Looper Handler, então o resultado é finalmente chamado de volta ao thread principal para executar .

Da mesma forma, o método síncrono execute também é o método execute para chamar o objeto de chamada okhttp3 e, finalmente, o método parseResponse é usado para analisar e encapsular o resultado da solicitação.

3 Resumo

Até o momento, a estrutura do Retrofit2 foi introduzida.Embora muitos detalhes sejam omitidos no processo, o princípio geral do processo ainda entende muito através do código fonte. Vamos resumir agora o princípio em poucas palavras:

O primeiro um , criar Retrofit objetos dentro do primeiro será a criação de diferentes Platform objetos de acordo com diferentes plataformas operacionais. Em seguida, inicialize os parâmetros por meio do modo construtor, como o uso de:

  1. Use o método baseUrl para definir a URL a ser acessada;
  2. Use seletivamente o método callFactory para criar um callFactory " network request executor factory " .Se esse método não for usado, um objeto OkHttpClient será criado;
  3. Use seletivamente o método callbackExecutor para criar um " callbackExecutor do método de retorno de chamada" callbackExecutor, se você não usar esse método, crie um defaultCallbackExecutor padrão, que é um objeto MainThreadExecutor com Looper Handler;
  4. Use seletivamente o método addCallAdapterFactory para adicionar " factory factory do adaptador de solicitação de rede " e acrescente um solicitante de rede padrão DefaultCallAdapterFactory;
  5. Use seletivamente o método addConverterFactory para adicionar " fábrica de conversor de dados ";
  6. Por fim, o Retrofit é instanciado através dos objetos criados acima.

De 2 , Criar Retrofit por um método genérico e um tipo de interface personalizada será passado para criar um pedido de costume objetos de interface, o objeto é usar o Proxy.newProxyInstance objeto proxy dinâmico.

O primeiro 3 , criar o objeto de chamada chamando o método de interface pedido personalizado,

  1. Primeiro, obtenha o valor da anotação no método de definição para criar um " Request Factory " RequestFactory e, em seguida, obtenha o callAdapter " adaptador de solicitação de rede ", "responseConverter do conversor de dados ", "responseConverter do conversor de dados ", callFactory " factory de executor de solicitação de rede " no objeto Retrofit e o recém-criado O RequestFactory " Request Factory " cria objetos CallAdapted herdados de HttpServiceMethod de acordo com o tipo;
  2. Como o proxy dinâmico é usado, o método de adaptação do objeto CallAdapted é finalmente chamado e, como o " adaptador de solicitação de rede " padrão é o objeto DefaultCallAdapterFactory, o objeto de Chamada criado dentro do método de adaptação é o objeto ExecutorCallbackCall.

O primeiro 4 , inicia um pedido de rede é para ser executado pelo enfileiramento e assíncrona e síncrona executar o método DefaultCallAdapterFactory.ExecutorCallbackCall. Esses dois métodos são concluídos por um objeto OkHttpCall, OkHttpCall encapsula internamente a solicitação de rede okhttp3. Depois que a solicitação é concluída, o resultado é retornado ao ExecutorCallbackCall e, em seguida, o resultado é retornado ao thread principal do chamador por meio do executor do método de retorno de chamada MainThreadExecutor com o Looper's Handler.

 

 

 

Publicado 106 artigos originais · elogiou 37 · 80.000 visualizações

Acho que você gosta

Origin blog.csdn.net/lyz_zyx/article/details/103728964
Recomendado
Clasificación