retrofit的设计原理(找一找第一次读源码的感觉)

481 阅读21分钟
  • 回顾,又整理一遍
  • 源码怎么读?
    • 拆成大块读,你从粗到细读。
    • 先写示例,然后跟着示例点到源码里面去,然后一步一步分析retrofit是怎么工作的。
    • 一定要跟着一步一步走下去,动手写示例,跳链接,写演示代码。

1.什么是retrofit?

  • 这是一个http的库,他是给android用,也可以给java后端用。
  • 之前他是给android用的,后来慢慢地做得足够散,足够的轻,足够的接口化,
  • 现在是android和java都可以用他了。

2.怎么用?

  1. 首先你要去做一个interface,这个interface声明了你的所有api的调用。就是http请求大概什么样的,通过这些方法声明来描述出来,而不需要写出具体的url。 在这里插入图片描述

  2. 创建一个retrofit的对象,再用这个对象创建出对象具体的interface实例,谁的实例?就是上面GitHubService的实例,就是你的接口列表的实例,这个接口列表包含你的所有接口。 在这里插入图片描述

  3. 用这个接口进行网络的调用。 在这里插入图片描述

以官网为例子大致写一下怎么用。

  1. 首先把这个retrofit加进来,添加依赖
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
  1. 创建一个名字为GithHubService的interface。然后声明一个get请求,这个格式不用背,用着就熟了,把请求路径填进去
public interface GitHubService {
    @GET("users/renwuxian/repos")
    Call<ResponseBody> getRepos();
}
  1. 创建retrofit对象,调用api
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://api.github.com")
                .build();

        GitHubService api =retrofit.create(GitHubService.class);

        api.getRepos().enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                System.out.println("success!");
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {

            }
        });//异步的
//        api.getRepos().execute();//同步的
  1. 添加权限
<uses-permission android:name="android.permission.INTERNET"/>
  1. 返回的是一个OKhttp的ResponseBody,所以需要做一个转换,添加一个转化器工厂,这个需要加json的支持
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
  • 添加转化器工厂
Gson gson = new Gson();
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();
  1. 这样接口申明里面就可以把ResponseBody改成json串对应的bean类了。
@GET("users/renwuxian/repos")
Call<ResponseBody> getRepos();
⬇️
@GET("users/renwuxian/repos")
Call<BaseBean> getRepos();
  • 对应的返回也要改,最后把结果打印出来
api.getRepos().enqueue(new Callback<BaseBean>() {
    @Override
    public void onResponse(Call<BaseBean> call, Response<BaseBean> response) {
        System.out.println("success!"+gson.toJson(response.body()));
    }

    @Override
    public void onFailure(Call<BaseBean> call, Throwable t) {

    }
});

3.源码从头到尾大致分析一下

  • 从哪入手?

    • 读源码不能一行一行读下来,从一个入口开始,从程序最直接交互的那个口--->enqueue
    • 我们知道enqueue是用来做网络请求的,如果我看懂了enqueue,是不是前面的东西都不用懂?
    • 有可能你的项目超级大,假如他有一个核心的配置,比如Retrofit,我从这点进去看,可能会给我一个过于宏大的场景了。
    • 我从最直接的来看,也许这个框架有8个功能,我从一个功能看,慢慢往别的地方去扩展。
  • enqueue做什么的?

    • 他是去后台去执行我们的网络请求,
    • enqueue在retrofit里面不是把每一个请求按照顺序去执行。
    • 而是执行这个方法以后,你的请求就会扔到他的列表里面,然后列表里面的东西马上就会被执行了,
      • 比如你有8个请求,这8个请求就一起执行了,并不会等某个请求结束。
      • 这个东西有什么作用呢?你立即执行为什么还要用队列啊?
        • 他会记录一下你同时运行的请求数,
        • 如果请求数太多了(大概是64个),他为了性能会给你停一停,别的新加进去的,我不会让他直接去执行了,先排着队,
        • 等别的让出位置了,让出足够的性能空间了,比如cpu,你们再去做。

1.找到入口:create()

  • 看源码:
    • enqueue点进去,这是一个抽象方法,再看位置,连个类都不是,他是一个接口,叫做Call。那现在完了,我不知道这个enqueue是怎么执行的,因为他是一个接口里面的抽象方法。
    • 那怎么办呢?我要知道他所在的这个对象当初是怎么创建的,也就是这个getRepos()他是怎么被创建的。
    • 但是getRepos()所在的api对象是GitHubService,他是一个我们刚刚声明的接口。那我们就去看这个api对象是怎么创建的。
GitHubService api = retrofit.create(GitHubService.class);
  • retrofit.create他是怎么做的?
    • 如果create里面还是接口的话,我得再链,如果没有的话就很好。
    • 点进去,太好了,终于是一个可以让我看的代码了。
  • 这create做了什么事情呢?
    • 他创建了接口对象,这个接口是所有包含了你网络定义api的接口,create是项目的核心,所有东西都是从这来的。
public <T> T create(final Class<T> service) {
  Utils.validateServiceInterface(service);
  if (validateEagerly) {
    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 {
          // If the method is a method from Object then defer to normal invocation.
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.adapt(okHttpCall);
        }
      });
}
  • 继续读代码,第一行
Utils.validateServiceInterface(service);
  • 点进去看一下。他是做验证的,做了两个验证,
    • 第一,你传进来的参数要是一个interface,
    • 第二,他的继承的接口不能大于0,
      • 这代表他必须是一个土生土长的接口,不能是继承了别的接口
static <T> void validateServiceInterface(Class<T> service) {
  if (!service.isInterface()) {
    throw new IllegalArgumentException("API declarations must be interfaces.");
  }
  // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
  // Android (http://b.android.com/58753) but it forces composition of API declarations which is
  // the recommended pattern.
  if (service.getInterfaces().length > 0) {
    throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
  }
}
  • 不用管它,不是关键点,
  • 同样的下面这一行,如果你做了激进化的配置的话,你就去验证一下,
    • 大致就是对你写的接口GitHubServic的合法性进行及早的验证。
  • 为什么要做这个配置呢?
    • 假如你做了这个配置,在你的Service被创建的一瞬间,就把所有的验证都做完了,那么他很利于你的调试工作,很早就发现你的代码写的不对,但不利于性能。
    • retrofit实际运行过程中,你用到什么方法,他就会稍微卡一瞬间,但是你卡一下没关系,你这卡一下那卡一下就分摊了,所以正式的项目中你不能这么做,不能让他过早的验证。因为过早的验证会导致集中验证。会被用户明显的知道卡一下。所以也不是关键点,这两个都是检查。
if (validateEagerly) {
  eagerlyValidateMethods(service);
}
  • 关键是这个,这么一行代码,这个newProxyInstance里面填了三个参数,其中第三个参数超长。
  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 {
          // If the method is a method from Object then defer to normal invocation.
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.adapt(okHttpCall);
        }
      });
  • newProxyInstance这个方法是什么?

  • 三个参数,

    • 第一个参数是classloader,
      • classloader可以理解为你要创建新的类的时候,你都要提供一个类加载器,来把这个类加载进来,不管这个类是你之前写过的,还是现场定义的一个类。
      • 所以这个classloader你不需要做任何工作, 你只需要把他拿出来,这个参数不用管,他就是说你给我提供一个classloader。你就随便扔一个吧,就把我所处的classloader给她。
    • 第二个参数是你提供一系列的接口,
      • 你提供一系列的interface,我这个newProxyInstance就会把所有的接口实现到一个对象里面。
      • 不过retrofit只提供了一个interface,就是装着我们所有api方法调用的那个接口。这个也好理解,但是他是怎么实现的呢?他是怎么把那些我声明了但是从来没有在任何地方实现的东西实现的呢?
    • 第三个参数。这个东西是什么?他是一个对象,
      • 对象里面有一个方法,叫做invoke的方法。
        • 你传过来一个对象,对象里面有一个方法,他实际上是什么?
        • 实际上是一个回调。什么是回调?
          • 你把这个东西给我传过来,我先放着,等会我需要用了,我调用一下。
  • invoke方法里面的东西很可能就是我们的关键点,但是先不说,

  • 先用代码模拟一下这个newProxyInstance他做什么事情。

    1. 先创建一个类,叫做RealService,实现了GitHubService,这个其实是newProxyInstance第二个参数要求实现的,而第一个参数其实提供了自动生成这个类所需要的类加载器,但是我们是模拟生成的过程,所以他就不重要了。
public class RealService implements GitHubService {
    @Override
    public Call<BaseBean> getRepos() {
        return null;
    }
}
  1. 往这个类里面添加功能,直接把第三个参数的回调方法粘进来
    • 忽略报红的部分,假装他是可以用的。然后修改getRepos方法。newProxyInstance实际上就是做的这个事情。(在Asm动态生成代理类的时候,具体可以看代理设计模式那一篇)
    • 第一,他会创建一个对象,这个对象是实现了你给我的所有接口,
    • 另外,他的每个方法我都会实现,通过调用我的invocationHandler的invoke方法,把你这个方法的方法信息给装进去,他实际上就是做的这么一个事情。
public class RealService implements GitHubService {
    InvocationHandler invocationHandler =  new InvocationHandler() {
        private final Platform platform = Platform.get();

        @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
                return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
                return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.adapt(okHttpCall);
        }
    };
    @Override
    public Call<BaseBean> getRepos() {
        Method method = null;
        try {
        // 方法的参数,注解其实都会解析出来,传递过去
            method = GitHubService.class.getMethod("getRepos");
            return (Call<BaseBean>)invocationHandler.invoke(this,method,null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}
  • 接下来我要知道invoke里面做了什么事情,我就知道retrofit是怎么做的了。
  • 那个代理的handler他又做了什么事情呢?
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
      throws Throwable {
    // If the method is a method from Object then defer to normal invocation.
    if (method.getDeclaringClass() == Object.class) {
        return method.invoke(this, args);
    }
    if (platform.isDefaultMethod(method)) {
        return platform.invokeDefaultMethod(method, service, proxy, args);
    }
    ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
    OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
    return serviceMethod.adapt(okHttpCall);
}
  • 一行一行看
if (method.getDeclaringClass() == Object.class) {
    return method.invoke(this, args);
}
  1. 首先解释下面这三行,
    • 这三行简单说没有用,他就是保证我的代码不出错。
    • 什么是DeclaringClass?
      • 就是你是在哪个类里面声明的这个方法,一个类里面的所有方法,只要他能调用的,要么是他申明的,要么是他的父类申明的。
    • 这里就是说,如果这个方法是Object类声明的,那我就直接调用。
      • 意思就是这个方法不是申明在GitHubService里面的话,比如一个toString()、hashCode()等等这种是在所有对象中都有的方法,那么你怎么申明的怎么用,我不改写你。
if (platform.isDefaultMethod(method)) {
    return platform.invokeDefaultMethod(method, service, proxy, args);
}
  1. 然后上面这几个也没有用。
    • 首先我要知道platform是什么?他做了什么?
    • 看platform的创建过程,get方法点进去
 private final Platform platform = Platform.get();
  • findPlatform(),这个方法没有任何描述,再点,有一个android的,一个java8,还有一个Platform();
  • 我猜测他是对于不同的平台他会有不同的行为。
private static final Platform PLATFORM = findPlatform();

static Platform get() {
  return PLATFORM;
}

private static Platform findPlatform() {
  try {
    Class.forName("android.os.Build");
    if (Build.VERSION.SDK_INT != 0) {
      return new Android();
    }
  } catch (ClassNotFoundException ignored) {
  }
  try {
    Class.forName("java.util.Optional");
    return new Java8();
  } catch (ClassNotFoundException ignored) {
  }
  return new Platform();
}
  1. 然后回去,这个方法就是看他是不是一个接口的默认方法,
    • 什么叫DefaultMethod?
      • 这是java8开始的一个新特性。
      • 我们都知道Java的interface是不能直接实现的,你的所有方法必须要让具体实现的那个类去实现, 你不能给出默认实现。而java8允许了。
      • 就这样,没别的了。这个东西对retrofit来说是没有用的,因为我们的接口都是不实现的。这个也没用。
if (platform.isDefaultMethod(method)) {
    return platform.invokeDefaultMethod(method, service, proxy, args);
}

2.找到核心的三行代码

  • 最后这三行就是retrofit实际做的事情了。
  • 那么又有问题了,这三行我都不认识,什么叫serviceMethod?什么叫okHttpCall?什么叫adapt?
  • 这三行我都想知道,我都看不懂,怎么办呢?
    • 我读代码的时候,需要找一唯一入口,因为有一个入口我能够更快的读懂一个完整的小事件,这个时候我有一个完整的方案,这个时候我的脑袋里面就可以清空一些内存出来,能继续读,
    • 那么现在有三行怎么办呢?我选谁呢?而且看起来也不知道谁更重要。而且他们彼此之间都有联系。
    • 这个时候我会选择每个都大致看一下,然后去判断我应该先细看谁。肯定要细看的,但是东西比较多的时候,我要大致浏览一下看我先看谁。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);

3.粗读三行代码

  • ServiceMethod点进来,有点蒙,文件也很大,

    • 看他的注释,把一个interface方法的调用适配到一个http的call(/** Adapts an invocation of an interface method into an HTTP call. */)。
    • 这句话大致没毛病,但是要我把他和代码联系起来我就联想不起来,我知道你在说什么但是我完全理解不了。
  • 在这我首先解释一个东西,什么叫adapter?

    • 我们平时做安卓开发会用到各种adapter,但是可能对什么叫adapter,什么是适配器没有足够的了解。
    • 适配器就是做转接的,就是把两孔的插头转成三孔。
    • 他把一个一个interface method适配到了一个http call。
    • 他是什么意思,就是把我们定义的api对应到一个http的call。
    • 不过这是我的猜测。这个时候你要问我这个方法是怎么用的我还是不知道。 注释讲的很少,代码也很长,拐回去,看看别的地方。
  • loadServiceMethod方法,我看看能不能把他看懂。又要链了,这一段东西是一个cash,我怎么知道的?

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;
}
  • serviceMethodCache的声明是一个Map,
  • 用Map来做cash非常常用。
  • cash:
    • 我这有没有这个东西呢?我这是否生成过,是否产生过这个东西呢?
    • 如果产生过,我的map里面能够查找到,那么我就直接用他,如果没有,我去生成一下,然后添加进来。
private final Map<Method, ServiceMethod<?, ?>> serviceMethodCache = new ConcurrentHashMap<>();
  • cash是这么一个工作原理,那么我需要去看他是在哪做的生成。点开Builder,看我能不能看懂。
result = new ServiceMethod.Builder<>(this, method).build();
  • 两个参数,
    • 一个是Retrofit,Retrofit是什么我也不知道,大致感觉上是一个总管的配置。
    • 还有一个是method,我定义在api里面的方法。
Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}
  • 参数好像也不多,接下来他会做三行
    • 一个是从他的方法取到每一个注解
    • 第二,取到他方法参数的每一个类型
    • 第三,取到方法参数的每一个注解(一个参数是可以加多个注解的)
  this.methodAnnotations = method.getAnnotations();
  this.parameterTypes = method.getGenericParameterTypes();
  this.parameterAnnotationsArray = method.getParameterAnnotations();
  • Builder创建完了,我看一下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);
}
  • 初始化完了以后,把你的各种初始化信息放到ServiceMethod
  return new ServiceMethod<>(this);
  • 用一个Builder模式创建了一个ServiceMethod,
  • 我知道很清楚是一个Builder模式,但是我不知道做了什么事,那么我现在要暂时先放弃一下,先不管他。等会我拐回来看。
ServiceMethod(Builder<R, T> builder) {
  this.callFactory = builder.retrofit.callFactory();
  this.callAdapter = builder.callAdapter;
  this.baseUrl = builder.retrofit.baseUrl();
  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;
  this.parameterHandlers = builder.parameterHandlers;
}
  • 现在我大概知道ServiceMethod的功能是一个封装了方法信息(注解、返回类型、参数注解...) 后,适配到一个okhttpcall,
  • 不是很明白,但是大概知道了一点意思。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);

这里简单说一下builder这种模式有什么好处。

  • builder我们一般怎么用的?
Person person = new Person.Builder()
    .name("xx")
    .gender("male")
    .age(25)
    .builder();
  • 他有什么好处?
    • 我现在这个人他的名字,年龄什么的是和其他属性相关的,他们可能互相之间属性是相关的。而且他们都有初始化成本。
    • 什么意思呢?比如:
      • Person person = new Person();
      • 然后我这个人就在内存里面做了初始化了,比如我是一个图形化程序,然后就把这个人画出来了,画了一个普普通通的人,然后,
      • person.setName("qiulong");
      • person.gendder("male");
      • 这个时候,就出问题了,我的程序里面默认的性别是女,你现在是男了,我现在要把这个女性形象给擦掉。,然后重新做一个男性出来。这个时候我之前做的女性他的性能就浪费了,时间也浪费了,而且我现在又要重新去创建那个男性,接下来又有,
      • person.age(25);
      • 我的系统里面都是默认24岁的,你这25岁了,完了,再把我这24岁的人给擦掉,然后重新画一个25岁的人。
    • 就是每个参数之间有挂钩,或者有初始化成本,一旦你的对象被生出来了,你再对他改动是有性能成本的。很多时候就没有必要。而builder就可以让你在创建之前什么额外工作都不做,我只是好像在做一个配置清单,最后直接初始化出来,这是builder最重要的好处之一。
    • 另外就是你的属性非常多,初始化起来很麻烦,用builder就可以一行定义下来。

4.粗读OkHttpCall

  • 接下来继续读源码,
  • 说到ServiceMethod,他是读了我api里面的method信息,然后把它转成了一个http的call。
  • 但是这个call是什么,怎么转的我不知道。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
  • 那么我再看一下OkHttpCall是什么?构造点进去,
  • 怎么这么简单?就两个参数。这就麻烦了,这个serviceMethod好像是根据方法做了转化,然后这个OkHttpCall他给我又非常简单,就这么一点,就是他把这两个参数存起来了,怎么办?
OkHttpCall(ServiceMethod<T, ?> serviceMethod, @Nullable Object[] args) {
  this.serviceMethod = serviceMethod;
  this.args = args;
}
  • 看一下OkHttpCall是个什么东西?
  • 首先,他是实现了Call这个接口,
final class OkHttpCall<T> implements Call<T> {...}
  • 记得Call是什么吗?
    • 我们在api里面定义的方法返回就是一个Call,retrofit教我们用的就是这个call,他们是一个东西。
public interface GitHubService {
    @GET("users/renwuxian/repos")
    Call<BaseBean> getRepos();
}
  • 那我先看一下OkHttpCall他的enqueue做什么事情,因为最终给用户响应的就是getRepos返回的Call的enqueue()。
api.getRepos().enqueue(new Callback<BaseBean>() {
    @Override
    public void onResponse(Call<BaseBean> call, Response<BaseBean> response) {
        System.out.println("success!"+gson.toJson(response.body()));
    }

    @Override
    public void onFailure(Call<BaseBean> call, Throwable t) {

    }
});
  • 这么一大堆,暂时先不看了。总之这个东西好像有点接近我的最终答案了,他们连上了。
  • 我在api定义的方法里面本来就要返回call对象,然后我用动态代理方法生成了一个动态对象,然后他的invoke方法终于给我一个call了。
@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "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();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

  if (canceled) {
    call.cancel();
  }

  call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      Response<T> response;
      try {
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        callFailure(e);
        return;
      }

      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
      callFailure(e);
    }

    private void callFailure(Throwable e) {
      try {
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}

5.粗读adapt

  • 可是这又懵了,这啥意思啊?adapter?不让我直接用?怎么办?看呗,反正前两行都看完了。
    • 第一行,我猜测是对方法的解析。
    • 第二行,我猜测是那个最终的call。
    • 但是到第三行我又不确定第二行是不是我猜测的东西了。但是我觉得前两行基本确定,因为第一行的东西还传给第二行作为参数了。那么我再确认一下我的猜测。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
  • 看完adapter,我就可以决定我这三行应该从哪来细看了。
T adapt(Call<R> call) {
  return callAdapter.adapt(call);
}
  • 我又开始烦了,又有个新东西出现了,叫做callAdapter,我先不管这个callAdapter是什么,先看这个adpter做了什么事情,点进去
T adapt(Call<R> call);
  • 又是个接口,那怎么办?这三行我都看不懂,先不管他,起码前两行跟我心中的那个结构是特别像的。我觉得你的代码能有多神奇呀?你不就是解析我的代码,然后生成一个call吗?这个看起来就特别像啊,第一行做解析,第二行做生成。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);

6.决定细读代码的顺序

  • 现在,这么三行的结构,我有两行有点清楚了,那么把这两行看完,我再看一下第三行,这就是我决定读代码的顺序了。

7.细读第一行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;
}
  • cash部分已经看过了,Builder我也看过了,我现在要看一下build()。
  • 很多时候,读到这,就比较痛苦了,他的大结构我已经知道了,就是Proxy.newProxyInstance(1,2,3),然后最终到这么三行。
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);
}
  • 看第一行
callAdapter = createCallAdapter();
  • callAdapter?这不是刚刚那玩意吗?大致看一下createCallAdapter()
private CallAdapter<T, R> createCallAdapter() {
  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.");
  }
  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);
  }
}
  • 上面是验证的,return上面的是核心代码
retrofit.callAdapter(returnType, annotations)
  • retrofit的calladapter方法被调过来传给我的ServiceMethod,那这个calladapter又是什么?
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
  return nextCallAdapter(null, returnType, annotations);
}
  • 链过去,代码有点长
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
    Annotation[] annotations) {
  checkNotNull(returnType, "returnType == null");
  checkNotNull(annotations, "annotations == null");

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

  StringBuilder builder = new StringBuilder("Could not locate call adapter for ")
      .append(returnType)
      .append(".\n");
  if (skipPast != null) {
    builder.append("  Skipped:");
    for (int i = 0; i < start; i++) {
      builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
    }
    builder.append('\n');
  }
  builder.append("  Tried:");
  for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
    builder.append("\n   * ").append(callAdapterFactories.get(i).getClass().getName());
  }
  throw new IllegalArgumentException(builder.toString());
}
  • 关键点是这
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
  • 现在回顾一下我要做什么,我刚刚看见一个calladapter,我要看他是怎么创建的。前面的代码都可以忘了,我要看calladapter是什么东西,看一下callAdapterFactorys,看一下哪个地方对他进行了修改。
final List<CallAdapter.Factory> callAdapterFactories;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
    List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
    @Nullable Executor callbackExecutor, boolean validateEagerly) {
  this.callFactory = callFactory;
  this.baseUrl = baseUrl;
  this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
  this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
  this.callbackExecutor = callbackExecutor;
  this.validateEagerly = validateEagerly;
}
  • 再看看谁调用了Retrofit(),点击Retrofit()。
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
    unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
  • 然后到这个地方,这个callAdapterFactories实际是在哪生成的呢?在上面一点点
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
  • 有两行,第一行他会把callAdapterFactories填进来,但是是空的。
  • 第二行他会加一个对象,调这个defaultCallAdapterFactory(),点进来
CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
  if (callbackExecutor != null) {
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }
  return DefaultCallAdapterFactory.INSTANCE;
}
  • ExecutorCallAdapterFactory()再点进来
final Executor callbackExecutor;

ExecutorCallAdapterFactory(Executor callbackExecutor) {
  this.callbackExecutor = callbackExecutor;
}
  • 看谁调用了callbackExecutor
return new ExecutorCallbackCall<>(callbackExecutor, call);
  • ExecutorCallbackCall点进去
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
  this.callbackExecutor = callbackExecutor;
  this.delegate = delegate;
}
  • 看谁调用了callbackExecutor
delegate.enqueue(new Callback<T>() {
  @Override public void onResponse(Call<T> call, final Response<T> response) {
    callbackExecutor.execute(new Runnable() {
      @Override public void run() {
        if (delegate.isCanceled()) {
          // Emulate OkHttp's behavior of throwing/delivering an IOException on cancellation.
          callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
        } else {
          callback.onResponse(ExecutorCallbackCall.this, response);
        }
      }
    });
  }

  @Override public void onFailure(Call<T> call, final Throwable t) {
    callbackExecutor.execute(new Runnable() {
      @Override public void run() {
        callback.onFailure(ExecutorCallbackCall.this, t);
      }
    });
  }
});
  • 最终走到这个地方,路上的都可以忘掉。
  • 记不记得前面也有一个onResponse和onFailure,最终链到这,也有一个onResponse和onFailure,他是把我的回调做了一个代理,他让callbackExecutor.execute去处理这个请求的成功和失败。
api.getRepos().enqueue(new Callback<BaseBean>() {
    @Override
    public void onResponse(Call<BaseBean> call, Response<BaseBean> response) {
        System.out.println("success!"+gson.toJson(response.body()));
    }

    @Override
    public void onFailure(Call<BaseBean> call, Throwable t) {

    }
});
  • execute是什么?
    • 他是做线程处理的东西,他可以去切线程。那么execute怎么切线程,他切线程有什么用处呢?
  • 看前面,我当时传过来的是callbackExecutor,我需要知道这个callbackExecutor做了什么,
    • 现在我知道我点过去,callbackExecutor做的是转嫁工作,他做的是一个代理工作,做的是一个委托工作,他让我最终返回的结果不管是成功还是失败,我需要转接一下。
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
  • 为什么转接?看一下callbackExecutor他做了什么,
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
  callbackExecutor = platform.defaultCallbackExecutor();
}
  • 他是空的,但是不害怕,我们刚才时候了Platform是android和java8通用的东西,我们看一下android有没有对应的实现。有没有对应的重写?
@Nullable Executor defaultCallbackExecutor() {
  return null;
}
  • 有,在底部,他叫MainThreadExecutor(),这是主线程Executor。
  • 同样的,我看一下他的execute()做了什么,
    • 这个execute()做了事情的代理。
    • 他的代理交给handler了。
    • 到这可能中间可能有点晕,确实我自己看的时候也晕。这里是什么?
      • 他把你的网络请求给切到前台了。怎么做到的?就是这个execute()里面。
  • okhttp他是那么做的,你在哪个线程做,我可以把他放到后台去,
  • retrofit做的就是把你所有的后台做到任务结果拿到前台来,帮你拿到主线程,这个就是callbackExecutor的工作。
  • 而这个callbackExecutor最终交给的callAdapterFactory,callAdapterFactory是工厂,创建的一个个callAdapter。他为不同的自定义api(GitHubService里)接口创建callAdapter ,每一个方法对应一个Call,每一个Call对应一个callAdapter。
  • 这个calladapter做了什么事情?线程切换。
static class Android extends Platform {
  @Override public Executor defaultCallbackExecutor() {
    return new MainThreadExecutor();
  }

  @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor == null) throw new AssertionError();
    return new ExecutorCallAdapterFactory(callbackExecutor);
  }

  static class MainThreadExecutor implements Executor {
    private final Handler handler = new Handler(Looper.getMainLooper());

    @Override public void execute(Runnable r) {
      handler.post(r);
    }
  }
}
  • 刚才读到第三行代码,我不知道adapter是做了什么事情,
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
  • 我只知道他用了callAdapter.adapt()。
  • 现在读到这,我本来想读ServiceMethod,
  • 但是不小心,我知道了callAdapter是干什么的了,
    • 他就是一个代理,帮我切一下线程。帮我把内容推到主线程去。那么好,我的一块石头落地了。
T adapt(Call<R> call) {
  return callAdapter.adapt(call);
}
  • 我给你们带的是有一点加速的,有点快的,有一些东西这一行代码与另一行代码之间怎么嵌套关系的,我是没有很详细地讲的。所以我的过程你没有听明白非常正常,但是他的作用,你要很清楚。
  • 结构明白了,那么中间的东西你要去了解就很容易。这一行就这个作用,
  • 但是他不仅仅是切线程的作用。他还可以做别的,他还可以做rxjava的适配。rxjava的适配也是这个地方。

那么我现在继续把前面两行也简单读一下。 都不能详细说,代码还是很复杂的,细节很多,但是结构还是很简单。 刚才

  • 看到loadServiceMethod()里的
result = new ServiceMethod.Builder<>(this, method).build();
  • builder进去,
  • 第一行我们看懂了。
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);
}
  • 第二行就是 responseType,你的api接口返回值类型。
 responseType = callAdapter.responseType();
  • 接下来都是结构简单,细节复杂的东西。
  • 比如createResponseConverter() ,
    • 什么叫responseConverter?
    • retrofit的底层是okhttp,我们可以得到的是什么?
    • 我们可以得到一个具体对象(besn)。
    • 我们得到的并不是一个ResponseBody,怎么做的?做的转换。怎么转换的,就是用的Converter。
responseConverter = createResponseConverter();
  • responseConverter点过去简单说一下,
Converter<ResponseBody, T> responseConverter;
  • 在retrofit里面,他有Converter这个东西,
    • Converter他做什么转换,Converter除了做返回结果他会给你转换成具体的对象,
    • 还有你请求的东西,有的时候你传入一个Integer,你需要转化成String才能去做网络数据的拼接,你们这个Converter就这么做的。
    • 还有有时候你要传一个图片,你传的是一个File,你怎么把File转换成一个RequestBody,也是靠的Converter。
    • Converter对你的请求和响应都会有转换作用。这是Converter的作用。

接下来

 parseMethodAnnotation(annotation);
  • parseMethodAnnotation,他是对你的方法去进行解读,对方法的每一个注解去进行解读。怎么解读的?简单看一下,我点进去就能够明白是做什么事情了,虽然我看不懂。
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) 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) {
    if (isFormEncoded) {
      throw methodError("Only one encoding annotation is allowed.");
    }
    isMultipart = true;
  } else if (annotation instanceof FormUrlEncoded) {
    if (isMultipart) {
      throw methodError("Only one encoding annotation is allowed.");
    }
    isFormEncoded = true;
  }
}
  • 对每一个注解有不同的解读。比如我随便点一个GET
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
  if (this.httpMethod != null) {
    throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
        this.httpMethod, httpMethod);
  }
  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);
}
  • 回到builder(),上面是对方法的注解的解读, 接下来,
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,他会去解读你的每一个参数,
  • 找个例子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是关键,也是解读一大堆注解
  • 对你的每一个参数类型的每一个注解进行解读,比如Url、Path
private ParameterHandler<?> parseParameterAnnotation(
    int p, Type type, Annotation[] annotations, Annotation annotation) {
  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);
    }
    ...
  • 对方法的解读过程中,他会去判断你这个方法用得对不对。
    • 比如你是一个get,但同时你又往里面加了body,那么我给你报错,get是取东西的,他的body里面不加东西,如果你加了我给你报错。
  • 到这个地方,可以看出来,retrofit除了比okhttp更好用之外,他还会对你的http规范使用有更多的要求,相应的也能让你更方便地去用这个东西。
  • 这些解读过程,你都可以暂时不知道,只需要知道ServiceMethod的build过程,
    • 就是把你的方法给解析出来,
    • 去读这个方法他具体的配置,读他的返回值,读他的每一个参数,
    • 把他们读完以后,解析一下,存下来,
    • 等到真正创建call的时候用到。

8.细读enqueue()

  • 到现在,已经证实
    • 第一行就是解读method,
    • 第二行是把ServiceMethod作为参数填进okhttpcall,
    • 第三行是做线程切换,这三行都解读完了
  • 但是我其实还有疑问,就是我之前我读不动的地方。enqueue。
ServiceMethod<Object, Object> serviceMethod = (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
  • 刚才我点过来一次,但是内容太多暂时放弃了,我觉得很恶心,但是现在不恶心了,因为只剩下这么一点了。
@Override public void enqueue(final Callback<T> callback) {
  checkNotNull(callback, "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();
      } catch (Throwable t) {
        throwIfFatal(t);
        failure = creationFailure = t;
      }
    }
  }

  if (failure != null) {
    callback.onFailure(this, failure);
    return;
  }

  if (canceled) {
    call.cancel();
  }

  call.enqueue(new okhttp3.Callback() {
    @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
      Response<T> response;
      try {
        response = parseResponse(rawResponse);
      } catch (Throwable e) {
        callFailure(e);
        return;
      }

      try {
        callback.onResponse(OkHttpCall.this, response);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }

    @Override public void onFailure(okhttp3.Call call, IOException e) {
      callFailure(e);
    }

    private void callFailure(Throwable e) {
      try {
        callback.onFailure(OkHttpCall.this, e);
      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  });
}
  • 这一部分只有两个关键
call = rawCall = createRawCall();
  • 我们的call是一个retrofit的call,他是一个外面的包装,
  • 真正进行网络请求的是okhttp,那么这个地方就生成了okhttp的call,这是第一个关键,第二个关键就是
 call.enqueue(new okhttp3.Callback() {...}
  • 看着一段是不是觉得有点奇怪,你不是在外面enqueue了一下,怎么里面又enqueue?为什么?

    • 因为这个call已经不是retrofit的call了,而是okhttp的call,
    • 他掉这个enqueue方法,然后做网络请求,
    • 做完之后,就把(okhttp3.Response )rawResponse解析了,
    • 解读完之后交给回调,这个callback也许是用户给你的,也许是calladapter(有可能去做线程切换)
  • 解析的东西大致看一下parseResponse(),大致看一下就能感受okhttp和retrofit他们的关系了,

    • code小于200大于300的报错,因为只有2xx才是正常,这之外的都会报错,
    • 但是301、302这些他们都会做自动跳转,这个是okhttp他会做,但是retrofit他不管这些,我这返回这个了我就报一个错。一般到不了retrofit,okhttp就会把这个事做了。
    • 然后204、205我会给你返回一个空对象。
  • 他做这些东西会在okhttp之外做一些额外的干涉,他让我们用得更舒服,但是会有一些限制。

Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
  ResponseBody rawBody = rawResponse.body();

  // Remove the body's source (the only stateful object) so we can pass the response along.
  rawResponse = rawResponse.newBuilder()
      .body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
      .build();

  int code = rawResponse.code();
  if (code < 200 || code >= 300) {
    try {
      // Buffer the entire body to avoid future I/O.
      ResponseBody bufferedBody = Utils.buffer(rawBody);
      return Response.error(bufferedBody, rawResponse);
    } finally {
      rawBody.close();
    }
  }

  if (code == 204 || code == 205) {
    rawBody.close();
    return Response.success(null, rawResponse);
  }

  ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
  try {
    T body = serviceMethod.toResponse(catchingBody);
    return Response.success(body, rawResponse);
  } catch (RuntimeException e) {
    // If the underlying source threw an exception, propagate that rather than indicating it was
    // a runtime exception.
    catchingBody.throwIfCaught();
    throw e;
  }
}
  • 他是会做parse(解析)的
T body = serviceMethod.toResponse(catchingBody);
  • 点进去
R toResponse(ResponseBody body) throws IOException {
  return responseConverter.convert(body);
}
  • 你给我一个okhttp的ResponseBody,我帮你把他转成你的方法所要返回的参数所要的类型。

  • OkHttpCall的enqueue做了什么?

    • 第一,创建了okhttp的call,
    • 然后,用它去做后台的请求,
    • 请求完之后,解析body,另外状态码不对的话我也会直接报错,
    • 解析完,交给callback,这个callback可能是一个calladapter(切换线程),也可能直接返回给用户
  • 最后只剩一点点,createRawCall()是怎么创建okhttp的call的?

private okhttp3.Call createRawCall() throws IOException {
  okhttp3.Call call = serviceMethod.toCall(args);
  if (call == null) {
    throw new NullPointerException("Call.Factory returned null.");
  }
  return call;
}
  • 又是serviceMethod.toCall(),他刚刚是用toResponse()转换的响应的结果的。这也是用toCall来转换一个call
  • serviceMethod是之前解析api里面接口后的半成品信息,然后用这些半成品转化成一个真正的call。 这个具体不用看了,他就是跟okhttp的一个交互。
okhttp3.Call toCall(@Nullable 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 callFactory.newCall(requestBuilder.build());
}
  • 到这,retrofit的大致源码就看完了。结构很简单。

4.adapter怎么用到rxjava呢?

  • 添加依赖
implementation 'com.squareup.retrofit2:adapter-rxjava:2.4.0'
  • 添加addCallAdapterFactory()
  • 为什么叫CallAdapterFactory,
    • 因为他是用来创建CallAdapter的,
    • 而且CallAdapter是可以转换线程,自动切换到主线程的东西,也可以是rxjava的Observable、Single
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();
  • 定义api接口的时候我可以用Call,也可以用Observable,他可以适配多个adapter
@GET("users/renwuxian/repos")
Call<BaseBean> getRepos();
@GET("users/renwuxian/repos")
Observable<BaseBean> getRepos1();
  • retrofit里面的是callAdapterFactories,他是一个工厂集合,不是一个工厂。
final List<CallAdapter.Factory> callAdapterFactories;