从一个最简单的例子来看Retrofit(二)

前情提要

上一篇博客把Retrofit的初始化大致了解了一下,Retrofit的初始化可以通过构造体也可以通过其内部类Builder进行创建。
链接:http://blog.csdn.net/wning1/article/details/78057571
本文接着上一篇向下分析源码:

还是粘贴一下Retrofit 官网上提供的一个简单的例子

Demo

interface:

 @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);

retrofit 网络请求,异步:

   Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        GitHubService service=retrofit.create(GitHubService.class);
        Call<List<Contributor>> repos = service.contributors("square", "retrofit");
        repos.enqueue(new Callback<List<Contributor>>() {
            @Override
            public void onResponse(Call<List<Contributor>> call, Response<List<Contributor>> response) {
                List<Contributor> contributors = response.body();
                for (Contributor contributor : contributors) {
                    System.out.println(contributor.login + " (" + contributor.contributions + ")");
                }
            }
            @Override
            public void onFailure(Call<List<Contributor>> call, Throwable t) {}
        });

代码分析

Retrofit初始化完毕,就该调用create()方法

create()

Retrofit初始化完成之后,就需要调用create()方法。看一下代码:

 public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) { //Retrofit初始化需要传递validataEagerly参数,如果该值为true,就是先去验证Github.class中定义的方法是否负责Retrofit的要求,不符合就抛出异常退出。默认情况validateEagerly 为false
      eagerlyValidateMethods(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 {

           //... 省略代码

            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

create() 方法是一个泛型方法,传入的是类型返回就是什么类型。在本例传入的是Github class 所以返回的就是Github 对象。对象的产生是通过Poxy代理出来的。Github对象并不会立即被创建出来,触发执行该段代码是在执行完demo中的service.contributors(“square”, “retrofit”); 这句代码。运行到loadServiceMethod并返回ServiceMethod 对象,本文将会loadServiceMethod相关联的代码,至于17,18行,OkhttpCall 下一篇blog在继续。

loadServiceMethod

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    ServiceMethod<?, ?> result = serviceMethodCache.get(method);
    if (result != null) return result;

    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder<>(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

该方法返回ServiceMethod对象。ServiceMethod 通过集合serviceMethodCache 得到,serviceMethodCache键:Method对象,值:ServiceMethod对象。如果找到值就返回,没有则创建ServiceMethod,并添加到集合中。

ServiceMethod 类主要的作用:解析Method方法中的注解,并存储到ServiceMethod

ServiceMethod是通过自身内部类Builder进行创建的。先看一下ServiceMethod构造体:

ServiceMethod

 ServiceMethod(Builder<R, T> builder) {
    this.callFactory = builder.retrofit.callFactory();
    this.callAdapter = builder.callAdapter;
    this.baseUrl = builder.retrofit.baseUrl(); //url Retrofit.Build baseUrl方法得到
    this.responseConverter = builder.responseConverter;
    this.httpMethod = builder.httpMethod; //网络请求方式:get or post
    this.relativeUrl = builder.relativeUrl; //相对路径  我会在Retrofit中设置baseurl
    this.headers = builder.headers;
    this.contentType = builder.contentType;
    this.hasBody = builder.hasBody;
    this.isFormEncoded = builder.isFormEncoded;
    this.isMultipart = builder.isMultipart;
    this.parameterHandlers = builder.parameterHandlers;//一维数组
  }

上面ServiceMethod的属性值通过内部类Builder赋值的。看一下Builder是怎么解析Method的。拿本文Demo来说,就是解析的如下方法:

    @GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(@Path("owner") String owner, @Path("repo") String repo);
ServiceMethod.Builder 构造体 :

ServiceMethod.Builder 构造体

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

ServiceMethod.Buildler 构造体方法需要传递Retrofit 和 Method 参数,Builder解析的也正是Method对象,这一部分涉及到的Method的api方法较多,要想理解代码还真需要查看一下java的api.

 - getAnnotations () //一维数组 Annotation[] :  @GET(...)
 - getGenericParameterTypes() //一维数组    Type[] 
 - getParameterAnnotations()//二维数组 Annotation[][] 
 - getGenericReturnType  获取返回数据类型 // Type
 - getRawType 获取<> 前面实际类型 例如Call<List<Contributor>> 值为Call

在本Demo中getAnnotations () @GET(“/repos/{owner}/{repo}/contributors”)
getGenericParameterTypes 获取是一个数组,里面存储着两个值:分别为onwer 和 repo 的参数类型String.class 。
getParameterAnnotations 获取的则是方法传递参数的注解数组,返回值是一个二维数组,为什么是一个二维数组呢?原因:每一个形参可有多个注解。如果我把本Demo中method改成如下:

@GET("/repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributors(@Part() @Path("owner") String owner, @Part()  @Path("repo") String repo);

那么二维数组存储值分别为:
【0】【0】 : @part 【0】【1】 : @part 【1】【0】: @part 【1】【1】 : @path

ServiceMethod.Builder 生成callAdapter :

着重看一下Builder的build()方法,对Method的解析几乎都在这个地方,一步一步的解析build()里面的代码:

 public ServiceMethod build() {

          callAdapter = createCallAdapter();
          responseType = callAdapter.responseType();

       return new ServiceMethod<>(this);
    }

首先build 调用 createCallAdapter 方法。

 private CallAdapter<T, R> createCallAdapter() {
      Type returnType = method.getGenericReturnType();
      ...//省略部分代码
      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);
      }
    }

首先获取到返回数据类型returnType,如果返回数据类型符合数据类型符合要求,则调用Retrofit的createCallAdapter中并返回CallAdapter。最终调用代码如下:

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

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

skipPast传入值为null,从上一篇文章我们知道 adapterFactoryies 目前就存储着一个值ExecutorCallAdapterFactory。

ExecutorCallAdapterFactory代码:

  @Override
  public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    final Type responseType = Utils.getCallResponseType(returnType);
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };
  }

在本Demo中getRawType返回值类型为为Call.class , getCallResponseType 为 List,ok ! 目前对ServiceMethod 中如下变量分别赋值:

  • callAdapter //ExecutorCallAdapterFactory. CallAdapter
  • responseType // List
ServiceMethod.Builder 获取转换工厂 :
 public ServiceMethod build() {
     responseConverter = 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);
      }
    }

最终调用Retrofit中nextResponseBodyConverter:

 public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable 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++) {
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }
 }

skipPast 为null ,method.getAnnotions 值为@GET(“/repos/{owner}/{repo}/contributors”)
converterFactories 中共存储两个值:BuiltInConverters 和 GsonConverterFactory ,for循环遍历BuiltInConverters 的到的converter 为null ,GsonConverterFactory 得到的converters不为null.则ServiceMethod 中如下变量分别赋值:

  • responseConverter //GsonConverterFacory
ServiceMethod.Builder : 解析方法注解
 public ServiceMethod build() {
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }
      //...省略部分代码 >主要判断hasBody为false情况下也就是请求方式为GET 不能使用 Multipart(文件上传) FormUrlEncoded(表单) 注解
}

parseMethodAnnotation:

 private void parseMethodAnnotation(Annotation annotation) {
       if (annotation instanceof GET) {
        parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
      }  else if (annotation instanceof POST) {
        parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
      }
      //... 省略部分代码
    }

parseHttpMethodAndPath:

   private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {

      this.httpMethod = httpMethod;
      this.hasBody = hasBody;

      if (value.isEmpty()) {
        return;
      }

      // Get the relative URL path and existing query string, if present.
      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);
        if (queryParamMatcher.find()) {
          throw methodError("URL query string \"%s\" must not have replace block. "
              + "For dynamic query parameters use @Query.", queryParams);
        }
      }

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

本Demo 传递的是@Get,执行完parseHttpMethodAndPath方法对ServiceMethod 中如下变量分别赋值:

  • httpMethod //String:GET
  • hasBody // false get形式没有请求体,Post 则有请求体
  • relativeUrl // /repos/{owner}/{repo}/contributors
  • relativeUrlParamNames // Set 集合存储着{ }中的字符串,分别为owner ,repo

其中parsePathParameter 则是通过正则表达式进行选取的,可自行查看源码。

ServiceMethod.Builder : 解析传递参数注解
 public ServiceMethod build() {
      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);
      }
 }

在本Demo中parameterCount 为2, parameterAnnotations 存储 @Path , 继续向下看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;
        }
        result = annotationAction;
      }
      return result;
    }

parseParameter方法中又调用了 parseParameterAnnotation 方法,该方法的代码实在是好长呀,只摘抄涉及到本Demo的代码啦!

 private ParameterHandler<?> parseParameterAnnotation(
        int p, Type type, Annotation[] annotations, Annotation annotation) {
      if (annotation instanceof Url) {
        gotUrl = true;
        //...省略部分代码
      } 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());

      } else if (annotation instanceof Query) {
        gotQuery = true;
        //...省略部分代码
      } else if (annotation instanceof QueryName) {
        gotQuery = true;
       //...省略部分代码
      }
      return null; // Not a Retrofit annotation.
    }

在本Demo中annotation 的为@Path,所以直接看该部分代码,首先gotPath = true , 可以看到如果是其他类型也会有相应的boolean值赋值。path.value 为owner 或者repo,然后又调用了retrofit.stringConverter

  public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
    checkNotNull(type, "type == null");
    checkNotNull(annotations, "annotations == null");

    for (int i = 0, count = converterFactories.size(); i < count; i++) {
      Converter<?, String> converter =
          converterFactories.get(i).stringConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<T, String>) converter;
      }
    }

    // Nothing matched. Resort to default converter which just calls toString().
    //noinspection unchecked
    return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
  }

在本Demo中converterFactories存储这BuiltInConverters 和 GsonConverterFactory 这两个类型对象,但是这两个对象都没有复写stringConverter 方法,所以最终返回BuiltInConverters.ToStringConverter.INSTANCE、

最后看一下parseParameterAnnotation 中 return new ParameterHandler.Path<>(name, converter, path.encoded());

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

    Path(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, @Nullable T value) throws IOException {
      if (value == null) {
        throw new IllegalArgumentException(
            "Path parameter \"" + name + "\" value must not be null.");
      }
      builder.addPathParam(name, valueConverter.convert(value), encoded);
    }
  }

Path 是ParameterHandler的内部类,复写的apply方法调用了RequestBuilder 的addPathParam

void addPathParam(String name, String value, boolean encoded) {
    if (relativeUrl == null) {
      // The relative URL is cleared when the first query parameter is set.
      throw new AssertionError();
    }
    relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
  }

将relativeurl { }中的内容替换成为parameterAnnocationd的value值。如本Demo中 /repos/{owner}/{repo}/contributors 转换之后为:/repos/owner/repo/contributors。

总结

至此Mehtod的注解则全部解析完毕。那么总结ServiceMethod :该类的作用就是解析Method数据(包括注解)存储到ServiceMethod中,便于接下来OkHttpCall 调用。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值