美文网首页
retrofit2源码分析(二)

retrofit2源码分析(二)

作者: nothingren | 来源:发表于2017-05-14 20:30 被阅读0次

    在第一章节讲到了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<Object>[] handlers = (ParameterHandler<Object>[]) 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<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.Path<>(name, converter, path.encoded());
    
          } 
    
        ……
    
        }
    

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

     static final class RelativeUrl extends ParameterHandler<Object> {
        @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源码分析(二)

          本文链接:https://www.haomeiwen.com/subject/wrdwzttx.html