Android开发Android文章Android开发

Android小知识-剖析Retrofit中ServiceMet

2018-11-04  本文已影响49人  爱读书的顾先生

本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢!

在上一节《Android小知识-剖析Retrofit中的网络请求接口》介绍了在Retrofit中通过动态代理获取网络请求接口的代理类,在执行网络请求时会执行InvocationHandler的invoke方法执行网络请求的相关操作。

    public <T> T create(final Class<T> service) {
        ...
        return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
                new InvocationHandler() {
                    private final Platform platform = Platform.get();

                    @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
                            throws Throwable {
                        //标记1
                        ServiceMethod<Object, Object> serviceMethod =
                                (ServiceMethod<Object, Object>) loadServiceMethod(method);
                        
                        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                        return serviceMethod.adapt(okHttpCall);
                    }
                });
    }

在标记1处调用了loadServiceMethod方法,这个方法在上一小节已经介绍过,从缓存集合serviceMethodCache获取对应方法的ServiceMethod,缓存集合中存在就直接返回,否则创建ServiceMethod对象,这个ServiceMethod对象对应的是网络请求接口中的一个方法相关参数的封装。

进入ServiceMethod类:

final class ServiceMethod<R, T> {
  ...

  private final okhttp3.Call.Factory callFactory;
  private final CallAdapter<R, T> callAdapter;

  private final HttpUrl baseUrl;
  private final Converter<ResponseBody, R> responseConverter;
  private final String httpMethod;
  private final String relativeUrl;
  private final Headers headers;
  private final MediaType contentType;
  ...
  private final ParameterHandler<?>[] parameterHandlers;

  ...
}

这个ServiceMethod是个泛型类,内部定义了很多成员变量,callFactory是我们的网络请求工厂,用于生产网络请求的Call对象,这个Call在Retrofit中是对OkHttp Call的封装;callAdapter是网络请求适配器,主要将网络请求适用于不同的平台,比如RxJava;baseUrl是网络基地址;responseConverter是数据转换器,将服务器返回的数据,比如json格式或者是xml格式等等,转换成Java对象;httpMethod是网络请求的方法,比如GET、POST等等;relativeUrl是网络请求的相对地址,比如网络请求接口中注解GET后的http请求地址;headers表示Http的请求头;contentType表示网络请求的body类型;parameterHandlers是方法参数的处理器。

ServiceMethod的实例是通过Builder来创建,进入ServiceMethod的Builder类:

    Builder(Retrofit retrofit, Method method) {
      this.retrofit = retrofit;
      this.method = method;
      this.methodAnnotations = method.getAnnotations();
      this.parameterTypes = method.getGenericParameterTypes();
      this.parameterAnnotationsArray = method.getParameterAnnotations();
    }

Builder构造函数中对成员变量进行赋值,传入retrofit和method分别赋值给Builder的成员变量retrofit和method,method表示网络请求方式,比如GET、POST等等,接着获取方法当中的注解赋值给methodAnnotations,parameterTypes获取的是网络请求接口中方法参数的类型,parameterAnnotationsArray获取的是网络请求接口方法中注解的内容。

Builder的相关初始化完毕后,通过build方法创建ServiceMethod对象:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      ...
    }

在build方法中通过createCallAdapter方法创建CallAdapter对象,createCallAdapter方法根据网络请求接口方法返回值和它的注解类型,从Retrofit中获取对应网络请求适配器。

createCallAdapter方法:

    private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      if (Utils.hasUnresolvableType(returnType)) {
        throw methodError(
            "Method return type must not include a type variable or wildcard: %s", returnType);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      //标记1
      Annotation[] annotations = method.getAnnotations();
      try {
        //noinspection unchecked
        return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create call adapter for %s", returnType);
      }
    }

通过method.getGenericReturnType()获取网络请求接口方法返回的类型,之后在标记2处,通过method.getAnnotations()获取网络请求接口方法中的注解,最后调用retrofit的callAdater方法返回CallAdapter对象,传入的就是前面获取的网络请求接口方法的返回类型和方法内的注解类型。

进入Retrofit的callAdapter方法:

  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

继续进入nextCallAdapter方法:

  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
    checkNotNull(returnType, "returnType == null");
    checkNotNull(annotations, "annotations == null");

    int start = callAdapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    ...
    throw new IllegalArgumentException(builder.toString());
  }

方法内前两行做非空判断,接着通过for循环遍历callAdapterFactories网络请求适配器工厂集合,看有没有合适的网络请求适配器工厂,如果没有抛出异常。

回到ServiceMethod的Builder类的build方法:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ...
    }

根据前面获取到的网络请求适配器之后,通过responseType方法获取网络适配器返回的数据类型。

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ...
      responseConverter = createResponseConverter();
      ...
    }

接着通过createResponseConverter方法获取数据解析器。

进入createResponseConverter方法:

    private Converter<ResponseBody, T> createResponseConverter() {
      Annotation[] annotations = method.getAnnotations();
      try {
        return retrofit.responseBodyConverter(responseType, annotations);
      } catch (RuntimeException e) { // Wide exception range because factories are user code.
        throw methodError(e, "Unable to create converter for %s", responseType);
      }
    }

通过method的getAnnotations方法获取网络请求接口中方法的注解,接着通过retrofit的responseBodyConverter方法获取Converter对象。

responseBodyConverter方法:

  public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
    return nextResponseBodyConverter(null, type, annotations);
  }

继续点进nextResponseBodyConverter方法:

  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    ...
    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        return (Converter<ResponseBody, T>) converter;
      }
    }

    ...
    throw new IllegalArgumentException(builder.toString());
  }

nextResponseBodyConverter方法内部遍历数据转换器工厂集合,从中获取合适的数据转换器,这里默认获取的是Gson的数据转换器。

回到ServiceMethod的Builder类的build方法:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ...
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      ...
    }

拿到数据转换器后,通过遍历网络请求接口方法的注解,parseMethodAnnotation方法主要是对网络请求接口方法上面的注解类型进行判断,同时根据注解类型对Builder的相关成员变量进行赋值。

回到ServiceMethod的Builder类的build方法:

    public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      ...
      responseConverter = createResponseConverter();
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      ...
      //标记1
      int parameterCount = parameterAnnotationsArray.length;
      parameterHandlers = new ParameterHandler<?>[parameterCount];
      for (int p = 0; p < parameterCount; p++) {
        ...
        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        ...

        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ...
      return new ServiceMethod<>(this);
    }

在标记1处,获取方法内注解的长度,从而创建参数解析器数组,接着遍历网络请求接口方法内的注解,并通过parseParameter方法来解析参数,最后通过new创建ServiceMethod对象并将配置好参数的Builder对象传递过去。

最后总结下这个build方法,主要根据网络请求接口内方法的返回值类型和方法中的注解,来从网络请求适配器工厂和数据转换器工厂,分别获取我们需要的网络请求适配器和数据转换器,然后根据参数上的注解获取到网络请求所需要的相关参数。


838794-506ddad529df4cd4.webp.jpg

搜索微信“顾林海”公众号,定期推送优质文章。

上一篇下一篇

猜你喜欢

热点阅读