retrofit2源码分析(二)

在第一章节讲到了ServiceMethod的toRequest()方法,下面就从toRequest()方法方法开始分析ServiceMethod,toRequest()的源码如下:

  Request toRequest(Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler[] handlers = (ParameterHandler[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);//这里是参数参数配置的核心
    }

    return requestBuilder.build();
  }
 
 

先来看一下handlers(也就是parameterHandlers)这个属性的功能。parameterHandlers的初始化在ServiceMethod的内部类Builder的build()方法中初始化。build()方法如下:

public ServiceMethod build() {
      callAdapter = createCallAdapter();
      responseType = callAdapter.responseType();
      if (responseType == Response.class || responseType == okhttp3.Response.class) {
        throw methodError("'"
            + Utils.getRawType(responseType).getName()
            + "' is not a valid response body type. Did you mean ResponseBody?");
      }
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      if (httpMethod == null) {
        throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
      }

      if (!hasBody) {
        if (isMultipart) {
          throw methodError(
              "Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
        }
        if (isFormEncoded) {
          throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
              + "request body (e.g., @POST).");
        }
      }

      int parameterCount = parameterAnnotationsArray.length;//方法的参数的所有注解
      parameterHandlers = new ParameterHandler[parameterCount];//初始化
      for (int p = 0; p < parameterCount; p++) {
        Type parameterType = parameterTypes[p];
        if (Utils.hasUnresolvableType(parameterType)) {//参数类型检查
          throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
              parameterType);
        }

        Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
        if (parameterAnnotations == null) {
          throw parameterError(p, "No Retrofit annotation found.");
        }
        //保存了参数类型和参数的注解
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }

      if (relativeUrl == null && !gotUrl) {
        throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
      }
      if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
        throw methodError("Non-body HTTP method cannot contain @Body.");
      }
      if (isFormEncoded && !gotField) {
        throw methodError("Form-encoded method must contain at least one @Field.");
      }
      if (isMultipart && !gotPart) {
        throw methodError("Multipart method must contain at least one @Part.");
      }

      return new ServiceMethod<>(this);
    }

这里先补充一点反射的知识。

Annotation[] annotations = method.getAnnotations();//获取方法的所有注解
Annotation[][] annos = method.getParameterAnnotations();//获取方法的参数的所有注解。
Type[] t = m.getGenericParameterTypes();//返回方法的参数列表

Utils.hasUnresolvableType()这个方法的源码如下:

  static boolean hasUnresolvableType(Type type) {
    if (type instanceof Class) {
      return false;
    }
    if (type instanceof ParameterizedType) {
      ParameterizedType parameterizedType = (ParameterizedType) type;
      for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
        if (hasUnresolvableType(typeArgument)) {
          return true;
        }
      }
      return false;
    }
    if (type instanceof GenericArrayType) {
      return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType());
    }
    if (type instanceof TypeVariable) {
      return true;
    }
    if (type instanceof WildcardType) {
      return true;
    }
    String className = type == null ? "null" : type.getClass().getName();
    throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
        + "GenericArrayType, but <" + type + "> is of type " + className);
  }

hasUnresolvableType()其实就是做了参数的类型检查。具体各个类型代表的含义,可以百度反射相关知识。

parseParameter()方法源码如下:

    private ParameterHandler parseParameter(
        int p, Type parameterType, Annotation[] annotations) {
      ParameterHandler result = null;
      for (Annotation annotation : annotations) {
        ParameterHandler annotationAction = parseParameterAnnotation(
            p, parameterType, annotations, annotation);

        if (annotationAction == null) {
          continue;
        }

        if (result != null) {
          throw parameterError(p, "Multiple Retrofit annotations found, only one allowed.");
        }

        result = annotationAction;
      }

      if (result == null) {
        throw parameterError(p, "No Retrofit annotation found.");
      }

      return result;
    }

接着看parseParameterAnnotation()的源码:

private ParameterHandler parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
      //如果注解是Url
      if (annotation instanceof Url) {
        if (gotUrl) {
          throw parameterError(p, "Multiple @Url method annotations found.");
        }
        if (gotPath) {
          throw parameterError(p, "@Path parameters may not be used with @Url.");
        }
        if (gotQuery) {
          throw parameterError(p, "A @Url parameter must not come after a @Query");
        }
        if (relativeUrl != null) {
          throw parameterError(p, "@Url cannot be used with @%s URL", httpMethod);
        }

        gotUrl = true;

        if (type == HttpUrl.class
            || type == String.class
            || type == URI.class
            || (type instanceof Class && "android.net.Uri".equals(((Class) type).getName()))) {
          return new ParameterHandler.RelativeUrl();//如果没有异常,返回Url对应的ParameterHandler。
        } else {
          throw parameterError(p,
              "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
        }

      } else if (annotation instanceof Path) {
        if (gotQuery) {
          throw parameterError(p, "A @Path parameter must not come after a @Query.");
        }
        if (gotUrl) {
          throw parameterError(p, "@Path parameters may not be used with @Url.");
        }
        if (relativeUrl == null) {
          throw parameterError(p, "@Path can only be used with relative url on @%s", httpMethod);
        }
        gotPath = true;

        Path path = (Path) annotation;
        String name = path.value();
        validatePathName(p, name);

        Converter converter = retrofit.stringConverter(type, annotations);
        return new ParameterHandler.Path<>(name, converter, path.encoded());

      } 

    ……

    }

RelativeUrl类的定义如下(其他的注解定义和使用方式都差不多,就不一一说明):

 static final class RelativeUrl extends ParameterHandler {
    @Override void apply(RequestBuilder builder, Object value) {
      builder.setRelativeUrl(value);
    }
  }

RequestBuilder的setRelativeUrl()方法定义如下:

  void setRelativeUrl(Object relativeUrl) {
    //url不能为空
    if (relativeUrl == null) throw new NullPointerException("@Url parameter is null.");
    this.relativeUrl = relativeUrl.toString();
  }
 
 

关于parameterHandlers就介绍到这里,总结起来就是parameterHandlers里面存放的是类似于RelativeUrl这样的类,专门用于处理各种注解。ServiceMethod的toRequest()方法,都会调用parameterHandlers里面的ParameterHandler的apply()方法。调用完之后,所有的参数都填入到RequestBuilder中去了。到此,Retrofit就完成了数据的收集功能。

你可能感兴趣的:(retrofit2源码分析(二))