Retrofit2 源码及流程分析

作者: Geeks_Liu | 来源:发表于2017-03-22 00:01 被阅读845次
    本篇提纲.png

    一.Retrofit中Builder模式完成初始化工作

    Retrofit现在已经是各种网络请求类APP的标配了,我们今天主要看下他的内部是如何解耦实现的
    首先展示一下基本用,也就是我们源码分析的入口代码:

        Retrofit retrofit = new Retrofit.Builder().
                baseUrl(BASE_URL).
                //addCallAdapterFactory(RxJavaCallAdapterFactory.create()). 如果有这句的话就没有下面的call.enqueue(new Call<List<Bean>>()那段了,直接就用了RxJava那一套了
                addConverterFactory(GsonConverterFactory.create()).
                build();
        Service service = retrofit.create(Service.class);
    
        Call<List<Bean>> call = service.getBeanLists(“username”);
        call.enqueue(new Call<List<Bean>>(){
            @Override
            public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
                beanList = response.body();
                ...     //doSomething();
            }
    
            @Override
            public void onFailure(Call<List<hot>> call, Throwable t) {
                Toast.makeText(getContext(), "读取失败,请检查网络设置", Toast.LENGTH_SHORT).show();
            }
        });
    
    public interface Service {
        @GET("{username}")
        Call<List<Bean>> getBeanLists(@Path("username") String username);
    }
    

    上述我们就创建了一个异步请求的Retrofit类,我们先从.Build();开始看起:

    public static final class Builder {
        private final Platform platform;    //选择平台:Android,java等
        private okhttp3.Call.Factory callFactory;   //okhttp的Call工厂类,自定义newCall将Request转为Call
        private HttpUrl baseUrl;            //okhttp中的类,保存解析过的url。baseUrl就是上面BASE_URL
        private final List<Converter.Factory> converterFactories = new ArrayList<>();//类型转换工厂列表
        private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();//CallAdapter工厂列表
        private Executor callbackExecutor;  //回调线程池
        private boolean validateEagerly;
    
        Builder(Platform platform) {
          this.platform = platform;
          converterFactories.add(new BuiltInConverters());  //添加默认的转换器(如果上面addConverterFactory中不添加的话)
        }
    
        public Builder() {
          this(Platform.get());
        }
        ......
    

    当程序执行完Retrofit retrofit = new Retrofit.Builder()这一句的时候,也就是执行了上述代码中的

        public Builder() {
          this(Platform.get());
        }
    

    这个方法,其中Platform.get()这个方法,实际上就是获取当前执行的平台,在Retrofit 2.0版本中,他支持Android,iOS,Java8三个平台。但是在2.2版本的源码中,删去了iOS平台选择的那部分源码,不知道是否还兼容iOS平台,这个不在本文讨论范围内,有兴趣的同学可以自行考证。判断完平台之后,赋值给Platform实例变量,我们都是Android平台。
      上面我们看了.Builder()方法,这个方法中实际上就行选择了一下平台。这个方法执行完之后,开始进行addCallAdapterFactory()addConverterFactory()等Build模式中的方法:

        /** Add converter factory for serialization and deserialization of objects. */
        public Builder addConverterFactory(Converter.Factory factory) {
          converterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    
        /**
         * Add a call adapter factory for supporting service method return types other than {@link Call}.
         */
        public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          adapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    

    可以看到,这里我们添加的RxJavaCallAdapterFactory.create()GsonConverterFactory.create()都加到了上面我们提到过的Builder类中的实例变量List<Converter.Factory> converterFactoriesList<CallAdapter.Factory> adapterFactories这两个List中,一遍后面解析使用。
      Build模式的最后一步.build()方法:

        public Retrofit build() {
          if (baseUrl == null) {    //baseUrl肯定是要设置的,不设置的话会抛出异常
            throw new IllegalStateException("Base URL required.");
          }
    
          //如果我们需要对OkHttp做出一些改进,比如添加链接超时什么得,就需要重新构建OkHttpClient并传入这里
          okhttp3.Call.Factory callFactory = this.callFactory;
          if (callFactory == null) {    //如果没有设置callFactory,则默认用OkHttpClient()
            callFactory = new OkHttpClient();
          }
    
          Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
          //读取设置的adapterFactories,也就是addCallAdapterFactory(RxJavaCallAdapterFactory.create())
          List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
          adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    
          // 读取converterFactories,也就是addConverterFactory(GsonConverterFactory.create())
          List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
    
          return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
              callbackExecutor, validateEagerly);   //最后一步,调用Retrofit构造函数,创建一个实例
        }
    

    上面的.build()中方法中,主要做了这么几件事情:
    ① 首先指定baseUrl,这个是必须指定的,否则会抛出异常
    ② 获取callFactory,如果没有设置,则默认返回new OkHttpClient()
    ③获取当前的callbackExecutor,即回调线程池。这个东西可以自己设,当然一般情况下我们是用平台默认设置的:

        Executor callbackExecutor = this.callbackExecutor;
          if (callbackExecutor == null) {
            callbackExecutor = platform.defaultCallbackExecutor();
          }
    
      static class Android extends Platform {       //我们一般都是Android平台看这部分就行了
        @Override public Executor defaultCallbackExecutor() {
          return new MainThreadExecutor();     //可以看到,defaultCallbackExecutor()中new MainThreadExecutor()
        }
    
        @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
          return new ExecutorCallAdapterFactory(callbackExecutor);
        }
    
        static class MainThreadExecutor implements Executor {
          //可以看到,这里实例化了一个获取了主线程Looper的Handler,也就是说这个Handler实例是像主线程中发送消息的
          private final Handler handler = new Handler(Looper.getMainLooper());
    
          @Override public void execute(Runnable r) {
            handler.post(r);    //采用Hanlder#post回调到主线程
          }
        }
      }
    

    ④adapterFactories,这个对象主要用于对Call进行转化,基本上不需要我们自己去自定义。如果我们像最上面代码中注释掉的那样添加一个addCallAdapterFactory(RxJavaCallAdapterFactory.create()),那么就不会有下面的call.enqueue(new Call<List<Bean>>(){这种的写法了,直接转换成RxJava那一套形式了。
    ⑤converterFactories,这个对象用于网络请求转换返回数据的转换。最开始那段示例代码中,我们用的是GsonConverterFactory,即Json数据解析,直接转换成我们需要的List<Bean>中的Bean实体类独对象了。
      当然,我们可以看到List<Converter.Factory> converterFactories,即converterFactories是一个Converter.Factory类型的对象,对于Converter.Factory类来说,网络请求转换返回数据的转换只是我们最常用的一个功能,我们如果看他的源码的话就会发现,该接口类中有三个方法,也就是三种功能:

    • public Converter<ResponseBody, ?> responseBodyConverter()用于将ResponseBody转换为指定类型,通常用于对响应结果的类型转换。

    • public Converter<?, RequestBody> requestBodyConverter()用于将指定类型转为RequestBody。一般用于将@Body,@Part,@PartMap转为RequestBody

    • public Converter<?, String> stringConverter()用于将指定类型转为String,用于将@Field,@FieldMap,@Path,@Query,@Header等注解的参数类型转为String。
      对于该接口类的用法我们在之后的使用中进一步解释。

    OK,Build完之后,调用Retrofit构造函数,创建一个实例:

      Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
          List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
          Executor callbackExecutor, boolean validateEagerly) {
        this.callFactory = callFactory;
        this.baseUrl = baseUrl;
        this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
        this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
        this.callbackExecutor = callbackExecutor;
        this.validateEagerly = validateEagerly;
      }
    

    到这里Build模式创建Retrofit的准备工作就完成了。

    二.retrofit.create中动态代理模式创建接口实例

    Build完之后,就该Service service = retrofit.create(Service.class);了:

      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, 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);
              }
            });
      }
    

    这里出现了一个重量级的设计模式——动态代理。好吧这个东西刚开始听到的时候我感觉也挺吓人的,遂研究之。关于动态代理的详细知识我们在这里不详细说明,不理解的话我们可以暂时把它理解成一个类/方法拦截器,我们在Service service = retrofit.create(Service.class);这句代码中,我们通过create(Service.class)这句代码传递给了上面的源码中的public <T> T create(final Class<T> service)方法,Service.class也就是我们定义各种接口的方法:

    public interface Service {
        @GET("{username}")
        Call<List<hot>> getBeanLists(@Path("username") String username);
    }
    

    因此,可以理解为,这里的(T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },new InvocationHandler()就是拦截下了service.class这个类,public Object invoke(Object proxy, Method method, Object[] args)就是在我们调用该类中的接口方法的时候,拦截下了我们所调用的方法,然后作进一步处理。
      关于动态代理,我们可以先做这样一个狭隘的理解,我们重点要看的是上面代码中的后三句代码:

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

    我们接下来要有很长的篇幅是围绕这三句代码展开的。

    1.loadServiceMethod(method);

      ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method); //首先从map中取看看是否已经缓存过
        if (result != null) return result;  //否则构造ServiceMethod
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result); //缓存方法到map中
          }
        }
        return result;
      }
    

    该方法传入的method就是上面动态代理的过程中拦截下的方法,也就是开头我们的示例中getBeanLists()方法。这里出现了一个ServiceMethod类,该类应该是Retrofit源码中最复杂的一个类了,它包含了将一个method转化为Call的所有的信息。我们从这一句开始看result = new ServiceMethod.Builder<>(this, method).build();

        Builder(Retrofit retrofit, Method method) {
          this.retrofit = retrofit;
          this.method = method;
          this.methodAnnotations = method.getAnnotations(); //方法注解
          this.parameterTypes = method.getGenericParameterTypes();  //参数类型
          this.parameterAnnotationsArray = method.getParameterAnnotations();  //参数注解
        }
    
      public ServiceMethod build() {
          callAdapter = createCallAdapter();    //创建CallAdapter,用来代理Call
          responseType = callAdapter.responseType();    //返回的是我们方法的实际类型,例如:Call<User>,则返回User类型
          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(); //创建ResponseConverter,转换ResponseBody为指定类型
    
          for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);  //遍历解析方法注解
          }
    
          ......
          int parameterCount = parameterAnnotationsArray.length;  //parameterAnnotationsArray为参数注解数组
          parameterHandlers = new ParameterHandler<?>[parameterCount];  //初始化ParameterHandler,用来处理参数相关
          for (int p = 0; p < parameterCount; p++) {    //遍历参数注解数组
            Type parameterType = parameterTypes[p]; //获取参数类型
            ......
            Annotation[] parameterAnnotations = parameterAnnotationsArray[p];   //获取参数注解数组
            ......
            //通过注解和参数类型,解析并赋值到parameterHandlers中
            parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
          }
    
          ......
          return new ServiceMethod<>(this);
      }
    
    1).callAdapter的创建——createCallAdapter()

    callAdapter 是Call方法的代理,把retrofit2.Call<T> 转为 T(注意和 okhttp3.Call 区分开来,retrofit2.Call<T> 表示的是对一个 Retrofit 方法的调用,也就是我们开始举得例子中Call<List<Bean>> getBeanLists的Call),这个过程会发送一个 HTTP 请求,拿到服务器返回的数据(通过 okhttp3.Call 实现),并把数据转换为声明的 T 类型对象(通过 Converter<F, T> 实现);

        private CallAdapter<T, R> createCallAdapter() {
          ......
          Annotation[] annotations = method.getAnnotations();
          try {
            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()方法:

      public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
        return nextCallAdapter(null, returnType, annotations);
      }
    
      public CallAdapter<?, ?> nextCallAdapter(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;
          }
        }
        ......
        throw new IllegalArgumentException(builder.toString());
      }
    
    还记得adapterFactories吗?

    这里出现了一个adapterFactories变量,还记得这个变量吗?好吧,你肯定忘了——这个就是我们开始举得例子中,注释掉的那一行//addCallAdapterFactory(RxJavaCallAdapterFactory.create()).代码所设置的东西,这里再贴一遍代码:

     public Builder addCallAdapterFactory(CallAdapter.Factory factory) {
          adapterFactories.add(checkNotNull(factory, "factory == null"));
          return this;
        }
    

    如果我们不addCallAdapterFactory()方法的话,那么在Retrofit.build()方法中,系统会添加一个平台默认的值:

        List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
        adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
    

    这里又出来了一个变量——callbackExecutor同样他也是我们之前说过的,向主线程中Post消息的回调线程池,忘了的同学可以回过头去看一看,
      OK,示例代码中我们注释掉了addCallAdapterFactory(RxJavaCallAdapterFactory.create()),也就是没有设置,那么这里应该会添加平台默认的CallAdapterFactory,我们追踪platform.defaultCallAdapterFactory(callbackExecutor)最终到了ExecutorCallAdapterFactory类的public CallAdapter<?, ?> get()方法中,该方法最终返回了一个new ExecutorCallbackCall<>(callbackExecutor, call):

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

    该ExecutorCallbackCall唯一做的事情就是将原本call的回调转发至UI线程,因为,我们之前说过,call.enqueue(new Call<List<Bean>>(){是开启一个异步线程。

    回到nextCallAdapter()中

    所以,CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);这句最终返回的就是“这个将原本call的回调转发至UI线程的ExecutorCallbackCall”,createCallAdapter()同样返回的是这个结果。
      通过上面的讲解,我们可以知道,这个CallAdapterFactory实际上就是决定网络请求回调方式的一个工厂。如果我们像之前注释掉的代码中的那样,添加一个addCallAdapterFactory(RxJavaCallAdapterFactory.create()),那么就会调用RxJava的回调方式返回结果,而不是默认的call.enqueue(new Call<List<Bean>>(){这种的。关于Retrofit和RxJava的配合使用,不在本文的讨论范围内。

    2).createResponseConverter()

    responseConverter 是 Converter<ResponseBody, T> 类型,负责把服务器返回的数据(JSON、XML、二进制或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象。
      createResponseConverter()方法拿到的是responseConverter对象,它根据我们构建retrofit时,addConverterFactory()添加的ConverterFactory对象来寻找一个合适的返回,寻找的依据主要看该converter能否处理你编写方法的返回值类型。
      什么意思?就是说,你在接收Json文件的时候,需要根据后台给你返回的Json格式来编写实体类,这样Gson()或者GsonConverterFactory.create()才能正确的解析数据成我们想要的实体类对象,否则就会转换失败。不过这个问题现在已经不是很严重了,因为有各种格式化Json数据的插件(如Android Studio 的GsonFormat插件),一般不会出错。

       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);
          }
        }
    
      public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
        return nextResponseBodyConverter(null, type, annotations);
      }
    
      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++) {
          Converter<ResponseBody, ?> converter =
              converterFactories.get(i).responseBodyConverter(type, annotations, this);
          if (converter != null) {
            //noinspection unchecked
            return (Converter<ResponseBody, T>) converter;
          }
        }
    
        ......
        throw new IllegalArgumentException(builder.toString());
      }
    

    这里我们贴了一遍源码,可以看到,整个执行的流程跟createCallAdapter()一模一样。如果我们不指定addConverterFactory()这个参数的话,默认实现为BuiltInConverters,仅仅支持返回值的实际类型为ResponseBody和Void,也就说明了默认情况下,是不支持Call<User>这类类型的。关于BuiltInConverters我呢这里不展开说了,对本篇文章意义不大,有兴趣自行看源码。

    3).遍历解析方法注解——parseMethodAnnotation(annotation)
        private void parseMethodAnnotation(Annotation annotation) {
    
                            /**请求方法注解**/
          if (annotation instanceof DELETE) {
            parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
          } else if (annotation instanceof GET) {
            parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
          } else if (annotation instanceof HEAD) {
            parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
            if (!Void.class.equals(responseType)) {
              throw methodError("HEAD method must use Void as response type.");
            }
          } else if (annotation instanceof PATCH) {
            parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
          } else if (annotation instanceof POST) {
            parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
          } else if (annotation instanceof PUT) {
            parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
          } else if (annotation instanceof OPTIONS) {
            parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
          } else if (annotation instanceof HTTP) {
    
                            /**自定义HTTP请求注解**/
            HTTP http = (HTTP) annotation;
            parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
          } else if (annotation instanceof retrofit2.http.Headers) {
    
                            /**请求头注解**/
            String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
            if (headersToParse.length == 0) {
              throw methodError("@Headers annotation is empty.");
            }
            headers = parseHeaders(headersToParse);
          } else if (annotation instanceof Multipart) {
    
                            /**FormUrlEncoded**/
            if (isFormEncoded) {
              throw methodError("Only one encoding annotation is allowed.");
            }
            isMultipart = true;
          } else if (annotation instanceof FormUrlEncoded) {
    
                            /**Multipart**/
            if (isMultipart) {
              throw methodError("Only one encoding annotation is allowed.");
            }
            isFormEncoded = true;
          }
        }
    
    解析请求方法注解和路径参数——parseHttpMethodAndPath()

    该方法主要用于解析我们设置的方法顶部的网络请求方式注解,如GET,POST等(@GET("{username}")),先判断是那种请求方式(上面的代码中已经判断完了),完了之后再具体解析请求方法中的路径参数。
      这里复习一下,Http协议的URL格式为:schema://host[:port#]/path/.../[;url-params][?query-string][#anchor],“?”前面(准确的说是从域名后的第一个“/”开始到最后一个“/”为止)是访问资源的路径从“?”开始到“#”为止,为参数部分,又称搜索部分、查询部分,参数与参数之间用“&”作为分隔符。,忘了的同学可以参照我的这篇文章:HTTP协议详解与Android相关基础网络编程
      在Retrofit中访问zhy的信息的两种形式:
    http://baseurl/user/zhy

    public interface IUserBiz{
        @GET("{username}")
        Call<User> getUser(@Path("username") String username);
    }
    

    http://baseurl/users?sortby=username

    public interface IUserBiz{
        @GET("users")
        Call<List<User>> getUsersBySort(@Query("sortby") String sort);
    }
    

    也即是说,对于接口方法中的注解参数来说,@Path()仍然对应的是BASE_URL的自路径,@Query()对应的才是“?”后面的参数查询。忘了的同学可以参照鸿阳大神的这篇文章:Retrofit2 完全解析 探索与okhttp之间的关系

    回到parseHttpMethodAndPath()源码中:

    int question = value.indexOf('?');  //查询参数开始的符号,“?”之后是查询的参数部分,“?”之前是查询的路径部分
    if (question != -1 && question < value.length() - 1) {
        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);    //解析{}路径参数保存到Set中
    
    static final String PARAM = "[a-zA-Z][a-zA-Z0-9_-]*";
    static final Pattern PARAM_URL_REGEX = Pattern.compile("\\{(" + PARAM + ")\\}");
    

    可以看到,这个方法就是解析路径参数,如果有“?”就把“?”之前的部分截取出来加以判断,如果这部分路径中有“{}”占位符,则抛出异常,让你用@Query()标签动态添加。
      最后一句this.relativeUrlParamNames = parsePathParameters(value);,这一句中parsePathParameters(value)这个方法主要就是解析“{}”中所包含的参数,然后存到一个set<>集合中,保存在relativeUrlParamNames这个全局变量中。

    4).解析每个参数使用的注解类型(诸如 Path,Query等)——ParameterHandler
    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);
    }
    

    每个参数都会有一个 ParameterHandler,由 ServiceMethod#parseParameter 方法负责创建,其主要内容就是解析每个参数使用的注解类型(诸如 Path,Query,Field 等),对每种类型进行单独的处理。
      上面代码中,我们直接从最后一句看起:parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);这句主要就是将每个方法中的参数解析成一个parameterHandlers[]数组储存:

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

    可以看到parseParameter方法中主要调用的是parseParameterAnnotation()方法来构建ParameterHandler对象,关于这个parseParameterAnnotation()方法由于源码是在是太长了(370+行代码),所以我们不贴出来,主要知道他做了哪几件事情就行:
      首先根据注解来判断来校验使用上有没有错误,比如@Query注解必须在@Path和@Url后使用,使用了@Url注解那么请求方法注解中不允许设置请求路径等等;然后获取相应Converter用于转换类型(String,ResponseBody),最后初始化相应ParameterHandler返回。

    好了到这里我们第二大点二.retrofit.create中动态代理模式创建接口实例中三句重点代码中的第一句loadServiceMethod()方法,中的ServiceMethod.build()就讲完了,为了避免大家迷失在茫茫的细节当中,我们再在这里帖一遍本篇的提纲:

    本篇提纲.png

    并再帖一遍代码:

    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;
    }
    
    public ServiceMethod build() {
      ......
      return new ServiceMethod<>(this);
    }
    

    这里我们还是要说一下这个build()方法最终Return的结果,也就是ServiceMethod()的构造函数:

    ServiceMethod(Builder<R, T> builder) {
        this.callFactory = builder.retrofit.callFactory();  //callFactory,默认为okhttp3.OkHttpClient
    
        //callAdapter,指定Retrofit.call网络请求的回调式,默认为ExecutorCallbackCall对象,也就是文章最开头
        //示例中的call.enqueue(new Call<List<Bean>>(){,当然我们可以指定为我们想要的的形式,如RxJava
        this.callAdapter = builder.callAdapter;
    
        this.baseUrl = builder.retrofit.baseUrl();//BASE_URL没什么好说的
    
        //responseConverter,负责转化服务器返回的数据成我们想要的实体对象,如果返回的是Json数据的话一般用Gson解析
        this.responseConverter = builder.responseConverter; 
    
        this.httpMethod = builder.httpMethod;
        this.relativeUrl = builder.relativeUrl;
        this.headers = builder.headers;
        this.contentType = builder.contentType;
        this.hasBody = builder.hasBody;
        this.isFormEncoded = builder.isFormEncoded;
        this.isMultipart = builder.isMultipart;
    
        //parameterHandlers,包装API 定义时每个方法的参数(诸如 Path,Query等),并在构造 HTTP 请求时设置参数
        this.parameterHandlers = builder.parameterHandlers;
    }
    

    这个构造函数中包含了ServiceMethod类的各种实例变量,这里我们需要重点注意几个变量:callFactorycallAdapterresponseConverterparameterHandlers,这四个变量我们之前都有过详细的讲解,可以结合注释复习一下。

    2.构建OkHttpCall()

    我们这里再帖一遍我们说过的那三句重点的代码:

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

    经过上面的分析,我们应该知道这个serviceMethod实际上就是一个包含了我们网络请求的callFactorycallAdapterresponseConverterparameterHandlers等重要信息的一个对象。接下来我们看第二句代码:
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);这句中实例化一个okHttpCall对象,构造函数仅仅是简单的赋值:

    OkHttpCall(ServiceMethod<T, ?> serviceMethod, Object[] args) {
        this.serviceMethod = serviceMethod;
        this.args = args;
    }
    

    接下来看第三句代码return serviceMethod.callAdapter.adapt(okHttpCall);,这句代码中的serviceMethod.callAdapter,也就是我们在1.1中讲的callAdapter,如何返回回调值的参数。经过上面的分析,假设我们这里没有指定addCallAdapterFactory(RxJavaCallAdapterFactory.create())这个参数,那么我们这里的callAdapter就是默认的CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      而这个adapterFactories是ExecutorCallAdapterFactory类的对象,我们去该类中看下:

    代码2.2(1)
    final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
      final Executor callbackExecutor;
    
      ExecutorCallAdapterFactory(Executor callbackExecutor) {
        this.callbackExecutor = callbackExecutor;
      }
    
      @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        //看这里看这里,这里重写了get方法,也就是默认的CallAdapter<?, ?> adapter =
        //apterFactories.get(i).get(returnType, annotations, this);中的get()方法
        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 serviceMethod.callAdapter.adapt(okHttpCall);中的adapt()代码
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    

    调用new ExecutorCallbackCall<>(callbackExecutor, call),这个类我们将在下节中讲解。
      这两个步骤都是之前讲过的,建议大家回过头去看下(好吧我写到这里都有点忘了之前写过)。也就是说,ExecutorCallbackCall仅仅是对Call对象进行封装,类似装饰者模式,只不过将其执行时的回调通过callbackExecutor进行回调到UI线程中去了

    三.发起网络请求

    首先我们再贴一遍文章开头的示例代码:

        Retrofit retrofit = new Retrofit.Builder().
                baseUrl(BASE_URL).
                //addCallAdapterFactory(RxJavaCallAdapterFactory.create()).
                addConverterFactory(GsonConverterFactory.create()).
                build();
        Service service = retrofit.create(Service.class);
    
        Call<List<Bean>> call = service.getBeanLists(“username”);
        call.enqueue(new Call<List<Bean>>(){
            @Override
            public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
                beanList = response.body();
                ...     //doSomething();
            }
    
            @Override
            public void onFailure(Call<List<hot>> call, Throwable t) {
                Toast.makeText(getContext(), "读取失败,请检查网络设置", Toast.LENGTH_SHORT).show();
            }
        });
    
    public interface Service {
        @GET("{username}")
        Call<List<Bean>> getBeanLists(@Path("username") String username);
    }
    

    经过我们上述的讲解,Retrofit底层的基础设施基本就讲完了,现在我们来发起一个网络请求。嗯,网络请求是在哪里发起的呢?实际上只要我们执行了Call<List<Bean>> call = service.getBeanLists(“username”);这一句之后,网络请求就开始了,然后我们只需要在call.enqueue(new Call<List<Bean>>(){中等着回调参数就行了。

    我们这里要讲的是,网络请求的数据,是如何下发到我们重写的

    call.enqueue(new Call<List<Bean>>(){
        @Override
        public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
        }
    
        @Override
        public void onFailure(Call<List<hot>> call, Throwable t) {
        }
    });
    

    中来的?

    1.从ExecutorCallAdapterFactory到OkHttpCall

    首先我们得接着上一节“构建OkHttpCall()”代码2.2(1)说起,我们说过,代码2.2(1)中实现了示例代码中“retrofit.create(HotService.class);”这句对应的源码中,三句关键代码的第三句return serviceMethod.callAdapter.adapt(okHttpCall);这句代码,我们把这个类的代码再贴一遍,这次顺便带上ExecutorCallbackCall这个静态内部类:

    ServiceMethod<Object, Object> serviceMethod =(ServiceMethod<Object, Object>) loadServiceMethod(method);
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    return serviceMethod.callAdapter.adapt(okHttpCall);
    
    代码3.1(1)
    final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
      final Executor callbackExecutor;
    
      ExecutorCallAdapterFactory(Executor callbackExecutor) {
        this.callbackExecutor = callbackExecutor;
      }
      ......(省略部分代码2.2(1)中的内容)
      @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
    
          @Override public Call<Object> adapt(Call<Object> call) {
            //我们说过,这里重写的adapt()就是三句关键代码中第三就的adapt,也即是说,这里的参数Call<Object> call
            //就是第二句中构建的OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    
      static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor;
        final Call<T> delegate;
    
        ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
          //这个callbackExecutor就是一个线程池对象,用来开启异步线程,没有什么好说的
          this.callbackExecutor = callbackExecutor;
          //在ExecutorCallbackCall类的构造函数中,又将okHttpCall对象递给delegate对象
          this.delegate = delegate;
        }
    
        @Override 
        public void enqueue(final Callback<T> callback) {                             (enqueue.1)
          if (callback == null) throw new NullPointerException("callback == null");
          //delegate是一个OkHttpCall类的对象,这一点要明确
          delegate.enqueue(new Callback<T>() {                                          (enqueue.2)
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {            (onResponse.1)
              callbackExecutor.execute(new Runnable() {
                @Override
                public void run() {
                  if (delegate.isCanceled()) {
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));  (onFailure.1)
                  } else {
                    callback.onResponse(ExecutorCallbackCall.this, response);                 (onResponse.2)
                  }
                }
              });
            }
    
            @Override 
            public void onFailure(Call<T> call, final Throwable t) {                       (onFailure.2)
              callbackExecutor.execute(new Runnable() {
                @Override 
                public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);                     (onFailure.1)
                }
              });
            }
          });
        }
    

    为什么要贴这么一串又臭又长的源码呢?可以看到上面的代码中我们标出了2个enqueue()方法,2个onResponse()方法,3个onFailure()方法~~好吧我刚开始看也看懵逼了,后来才发现,这里有两个接口在嵌套使用,所以必须对照源码才能说的清楚。

    2个enqueue()方法

    我们要分清楚这两个enqueue()方法都是干什么的。首先我们看(enqueue.1)处的这个enqueue方法,可以看到他是@Override,即重写的方法,重写的谁的呢?当然是ExecutorCallbackCall类实现的Call<T>中的方法,这里需要注意一点,这里的Call<T>retrofit2.call<T>,不要和待会出现的okhttp3.Call搞混了。
      我们再来看(enqueue.2)处的enqueue,这个enqueue是由delegate调用的,我们之前强调过,delegate是OkHttpCall类的对象,也就是说,这里的enqueue(new Callback<T>() {实际上是OkHttpCall类中传过来的,我们进入到该类中,看看该类中的enqueue()方法(retrofit-2.2.0-source.jar/retrofit2/OkHttpCall):

    代码3.1(2)
    public void enqueue(final Callback<T> callback) {
        if (callback == null) throw new NullPointerException("callback == null");
    
        okhttp3.Call call;
        Throwable failure;
    
        synchronized (this) {
          if (executed) throw new IllegalStateException("Already executed.");
          executed = true;
    
          call = rawCall;
          failure = creationFailure;
          if (call == null && failure == null) {
            try {
              call = rawCall = createRawCall(); //createRawCall()方法创建原始Call,即okhttp3.Call对象
            } catch (Throwable t) {
              failure = creationFailure = t;
            }
          }
        }
    
        if (failure != null) {
          callback.onFailure(this, failure);
          return;
        }
    
        if (canceled) {
          call.cancel();
        }
    
        call.enqueue(new okhttp3.Callback() {   //调用okhttp3.Call发起一个enqueue()异步请求
        //注意这里的enqueue()方法是OkHttp中的"真"异步请求方法,前面的都是自定义的"假"方法
        @Override
          public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)   (onResponse.4)
              throws IOException {
            Response<T> response;
            try {
              response = parseResponse(rawResponse);    //解析服务器返回的内容,生成response对象
            } catch (Throwable e) {
              callFailure(e);
              return;
            }
            callSuccess(response);
          }
    
          @Override
          public void onFailure(okhttp3.Call call, IOException e) {      (onFailure.4)
            try {
              callback.onFailure(OkHttpCall.this, e);
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callFailure(Throwable e) {
            try {
              //这里通过callBack将错误结果返回给ExecutorCallbackCall类
              callback.onFailure(OkHttpCall.this, e);                       (onFailure.3)
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
    
          private void callSuccess(Response<T> response) {
            try {
              //这里通过callback回调接口将网络请求并解析后的结果返回给ExecutorCallbackCall类
              callback.onResponse(OkHttpCall.this, response);                           (onResponse.3)
            } catch (Throwable t) {
              t.printStackTrace();
            }
          }
        });
      }
    

    OkHttpCall类中的enqueue()方法很简单,实际上就是先创建一个okhttp3.Call对象,然后利用这个okhttp3.Call发起一个异步请求,完了时候讲返回的结果通过callback接口返回给ExecutorCallbackCall类。
      我们需要注意这里的调用关系:

    3.1(1)
    delegate.enqueue(new Callback<T>() {
    
    3.1(2)
    public void enqueue(final Callback<T> callback) {
    

    也就是说,代码3.1(1)中(enqueue.2)处的new Callback,就是我们代码3.1(2)中的参数final Callback<T> callback,所以我们在代码3.1(2)中的(onFailure.3),(onResponse.3)都会通过这个callback实例回调到代码3.1(2)中的(onResponse.1)和(onFailure.2),这个对应关系一定要看清楚。
      我们再强调一遍,代码3.1(2)中的(onResponse.1)和(onFailure.2)两个@Override类型的方法,它们是OkHttpCall类(3.1(2))中(onFailure.3)和(onResponse.3)两处的方法,的回调!!!
      而OkHttpCall类(3.1(2))中(onFailure.4)和(onResponse.4)两处重写的方法,它们重写的是call.enqueue(new okhttp3.Callback() {这个OkHttp异步请求的接口的,onFailure和onResponse方法,表示OkHttp网络请求的结果。
      是不是感觉脑子晕晕的?没错,不知道Squareup为什么这段代码写的可读性这么差~~~嗯,更精彩的还在后面,这里假设你已经理解了上面这几个长的一模一样但是却代表不同意义的几个方法和回调。

    回到ExecutorCallAdapterFactory(3.1(1))类中,如果你已经理解了上面所说的话,就应该知道,(onResponse.1)和(onFailure.2)这两个重写方法,是OkHttpCall类(3.1(2))中OkHttp的异步网络请求所回调回来的结果。我们再贴一下代码:

    static final class ExecutorCallbackCall<T> implements Call<T> {
        final Executor callbackExecutor;
        final Call<T> delegate;
        ......
        @Override 
        public void enqueue(final Callback<T> callback) {                             (enqueue.1)
          if (callback == null) throw new NullPointerException("callback == null");
          //delegate是一个OkHttpCall类的对象,这一点要明确
          delegate.enqueue(new Callback<T>() {                                          (enqueue.2)
            @Override
            public void onResponse(Call<T> call, final Response<T> response) {            (onResponse.1)
              callbackExecutor.execute(new Runnable() {
                @Override
                public void run() {
                  if (delegate.isCanceled()) {
                    callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));  (onFailure.1)
                  } else {
                    callback.onResponse(ExecutorCallbackCall.this, response);                 (onResponse.2)
                  }
                }
              });
            }
    
            @Override 
            public void onFailure(Call<T> call, final Throwable t) {                       (onFailure.2)
              callbackExecutor.execute(new Runnable() {
                @Override 
                public void run() {
                  callback.onFailure(ExecutorCallbackCall.this, t);                     (onFailure.1)
                }
              });
            }
          });
    }
    

    我们再来看看这个(onFailure.1)和(onResponse.2)这两种方法,这里有出现了一个callback,这里的callback又是什么呢?Ok,如果你看源码的化就会发现,这个Callback是(enqueue.1)处:

    @Override 
        public void enqueue(final Callback<T> callback) {
    

    这个重写的enqueue()的参数,我们之前说过,这里的enqueue重写的是Call<T>接口中的方法,因为ExecutorCallbackCall<T> implements Call<T>,而另一端回调这个Call<T>接口的地方,是在我们缩写的代码中:

    call.enqueue(new Call<List<Bean>>(){
        @Override
        public void onResponse(Call<List<Bean>> call, Response<List<Bean>> response) {
        }
    
        @Override
        public void onFailure(Call<List<hot>> call, Throwable t) {
        }
    });
    

    看到了吧?(onFailure.2)(onResponse.2)这两处的callback回调,最终回调到了我们所写的call.enqueue(new Call<List<Bean>>(){中,并且携带着已经转换成我们想要的特定实体类型的数据。
      到这里,我们已经拿到了我们想要的数据,整个分析的过程也就走完了。

    相关文章

      网友评论

        本文标题: Retrofit2 源码及流程分析

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