划水:Retrofit三步走:request篇

​ 在流程梳理篇,我们介绍了ServiceMethod是其retrofit的核心部分,这篇我们就着重分析retrofit的ServiceMethod这个处理类

build建造者部分

对于ServiceMethod这部分的build,其构造如下:

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

这里传入了retrofit本身和目标的方法method
 
从method的getAnnotations/getGenericParameterTypes/getParameterAnnotations
这些方法中,可以看出retrofit这部分就是想方设法从method上获取到所有的信息

从上面的构造入手,一下子就想到在使用的时候我们的一些做法,举例:

@FormUrlEncoded
    @POST("openapi.do")
    public abstract Call<TranslateBean> hello(@Field("keyfrom") String keyfrom,
                                              @Field("key") String key);

众所周知,一个request的组成基本上参数部分都是key-vale形式组成,那就不难理解为什么retrofit要求我们从通过方法注解/参数注解这些方式传入对应的关系了

理解了参数部分,我们看看build建造者最关键的方法build方法:

build方法较多,我们先折叠起来,看前半部分:

public ServiceMethod build() {
    callAdapter = createCallAdapter();
    responseType = callAdapter.responseType();
    responseConverter = createResponseConverter();
      ...省略部分代码
    return new ServiceMethod<>(this);
}

build方法上首先创建了一个callAdapter,提起callAdapter不免立马想到我们使用时传入的RxJavaCallAdapterFactory部分,我们顺着createCallAdapter看看跟我们RxJavaCallAdapterFactory有没有关系,

private CallAdapter<T, R> createCallAdapter() {
  		/**
  		 * 首先通过method获取返回值类型,紧跟着对返回值类型合法性验证
  		 */
      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.");
      }
  		/**
  		 * 接着获取方法上的注解,根据返回值类型和方法上的注解,调用retrofit的callAdapter
  		 */
      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);
      }
    }

而对于retrofit的callAdapter方法其上注解是这样描述的:

 /**
   * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
   * #callAdapterFactories() factories}.
   *
   * @throws IllegalArgumentException if no call adapter available for {@code type}.
   */
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

即返回这种返回值类型的callDApter从callAdapterFactories中,那就很显然了,那就跟我们预想的一样,RxJavaCallAdapterFactory中返回目标返回值类型的callAdapter

对于callAdapter这部分是retrofit的高明之处,通过这个callAdapter大大增加了其语言的扩展性

CallAdapter部分

在callAdapter这里呢,只有两个方法,一个是Type responseType();,另一个是T adapt(Call<R> call);

这个方法是返回在请求响应时我们接收的bean的值类型对象
Type responseType();
而最后这个方法是返回一个okhttp执行请求的call代理对象
T adapt(Call<R> call);

顺着上面的思路继续,在build方法中,紧跟着从callAdapter的responseType中获取返回值类型,根据这个返回值类型,调用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);
      }
    }
这个方法就与callAdapter很相似了,也是通过获取method方法上的参数,根据返回值类型和注解,调用retrofit的responseBodyConverter

对于responseBodyConverter这部分处理与callAdapter极其的相似

ResponseBodyConverter部分

一提到相似,我们也就能反应过来,我们传入的GsonConverterFactory,也是根据我们的要求返回我们所要的ResponseBodyConverter

/**
   * Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available
   * {@linkplain #converterFactories() factories} except {@code skipPast}.
   *
   * @throws IllegalArgumentException if no converter available for {@code type}.
   */
  public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
      Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      /**
       * 通过converterFactory找到我们要的converter来进行转换
       */
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
		...省略部分代码...
  }

既然通过createCallAdater和createResponseConverter这两个方法,把耦合的入口和出口都处理好了,下面就是进入参数处理的阶段了:

		/**
		 * 通过method的注解遍历,对method的注解进行处理
		 */
		for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      ...省略部分代码...

      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);
      }
      ...省略部分代码...

剩余的方法主要就是parseMethodAnnotation和parseParameter这两个方法了

parseMethodAnnotation

在这里插入图片描述

这里只剪辑parseMethodAnnotation不过殊途同归,最终处理都是在parseHttpMethodAndPath中,对于parseHttpMethodAndPath

parseHttpMethodAndPath

private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
      ...省略部分代码...
      int question = value.indexOf('?');
  		/**
  		 * 对参数注解和参数值进行拼接
  		 */
      if (question != -1 && question < value.length() - 1) {
        // Ensure the query string does not have any named parameters.
        String queryParams = value.substring(question + 1);
        Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
        ...省略部分代码...
      }

      this.relativeUrl = value;
      this.relativeUrlParamNames = parsePathParameters(value);
    }

static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
  static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);

/**
 * 完成对url的处理
 */
static Set<String> parsePathParameters(String path) {
    Matcher m = PARAM_URL_REGEX.matcher(path);
    Set<String> patterns = new LinkedHashSet<>();
    while (m.find()) {
      patterns.add(m.group(1));
    }
    return patterns;
  }
最终我们得到目标方法的请求路径

由于parseParameterAnnotation情况分类比较多,这里仅拿field来进行讲解说明

...省略部分代码...
/**
 * 首先获取字段名称
 */
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();

gotField = true;

/**
 * 首先获取值类型
 */
Class<?> rawParameterType = Utils.getRawType(type);
/**
 * 如果值类型是Iterable的子类
 */
if (Iterable.class.isAssignableFrom(rawParameterType)) {
  
   if (!(type instanceof ParameterizedType)) {
            throw parameterError(p, rawParameterType.getSimpleName()
                + " must include generic type (e.g., "
                + rawParameterType.getSimpleName()
                + "<String>)");
   }
   ParameterizedType parameterizedType = (ParameterizedType) type;
  /**
   * 如果值类型是Iterable的子类,通过getParameterUpperBound获取实际类型的类型
   */
   Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
  	/**
     * 通过type和注解找到转换的converter
     */
   Converter<?, String> converter =
              retrofit.stringConverter(iterableType, annotations);
  	/**
  	 * 将转换器/字段名称和字段是否encode处理存放在ParameterHandler的Field中
  	 */
   return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
   Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
   Converter<?, String> converter =
              retrofit.stringConverter(arrayComponentType, annotations);
   return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
    Converter<?, String> converter =
              retrofit.stringConverter(type, annotations);
    return new ParameterHandler.Field<>(name, converter, encoded);
}

将所有paramterHandler存放在builder的parameterHandlers中

ParameterHandler

ParameterHandlerd的实现不同实现有很多,有Body/RawPart/FieldMap/Field等等,这里用Field举例:

 static final class Field<T> extends ParameterHandler<T> {
    private final String name;
    private final Converter<T, String> valueConverter;
    private final boolean encoded;

    Field(String name, Converter<T, String> valueConverter, boolean encoded) {
      this.name = checkNotNull(name, "name == null");
      this.valueConverter = valueConverter;
      this.encoded = encoded;
    }

    @Override void apply(RequestBuilder builder, T value) throws IOException {
      if (value == null) return; // Skip null values.
      builder.addFormField(name, valueConverter.convert(value), encoded);
    }
  }

所有实现最关键的apply方法,向RequestBuilder中addFormField操作 构建请求数据

到这里Builder相关的方法就结束了

toRequest

toRequest方法是ServiceMethod其中的一个方法,从上面我们片面的了解parameterHandler帮我们构建form请求数据,这个方法就是ServiceMethod帮助我们统一进行对Request的创建

Request toRequest(Object... args) throws IOException {
  	/**
  	 * 根据目标方法/baseUrl等创建RequestBuilder
  	 */
    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 + ")");
    }
		/**
  	 * 将之前构建的所有paramterhandler进行request处理
  	 */
    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

至此retrofit部分的request处理就到这结束了,由于reqeustBuilder内容相对清晰,容易分析,这里就不加大篇幅来阐述这里的内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值