Retrofit2源码分析(一)

前言

很早之前就开始接触Retrofit,自己也写了一个项目,但是一直没有深入研究过源码。


正文

版本

v2.0.2

项目结构

image.png

源码文件并不多,所以相对看起来还是比较方便的。


接口

阅读源码,我认为可以先了解作者定义的接口,这样可以有助于我们把握整体的流程,而且优秀的代码也是依赖接口而不是具体的实现。所以要阅读好的三方框架,最好是先了解他的接口,非常有助于源码阅读。

这里主要有4个接口。我简单介绍。

Call

真正发出请求的对象接口

CallAdapter

可以把Call对象转化为另外一个对象,如Observable

Callback

请求回调

Converter

把请求到的数据进行转化

先对所有的接口有个大致的了解


从一个简单的例子入手

  var retrofit = Retrofit.Builder()
                .baseUrl("http://www.baidu.com")
                .build()
        retrofit.create(TestApi::class.java)
                .test("http://www.baidu.com")
                .enqueue(object : Callback<ResponseBody> {
                    override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>?) {
                    }

                    override fun onFailure(call: Call<ResponseBody>?, t: Throwable?) {
                    }
                })
...
interface TestApi{
   @GET
    fun test(@Url url:String):Call<ResponseBody>
    }
第一步: Retrofit构建

从上面例子中可以看出,创建Retrofit时候,只有添加有一个必须添加的baseUrl

  public Retrofit build() {
      if (baseUrl == null) {
        throw new IllegalStateException("Base URL required.");
      }

 okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

      // Make a defensive copy of the converters.
      List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

      return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
          callbackExecutor, validateEagerly);
    }

除了可以添加baseUrl,其实还有2个可选的参数可以添加。

  1. Convert 的实现对象的工厂类
  2. CallAdapter的实现对象的工厂类

为了先最简单地了解整个源码的流程,所以这些可选的参数我都先不加。

可以从上面的build的代码中,可以看出,会创建一个
List<CallAdapter.Factory>List<Converter.Factory>用来存放传进来的参数。所以我们可以知道,Retrofit是可以传入多个CallAdapter.FactoryConverter.Factory

但是这里我们先不管,先往下走。

第二步:使用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, 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 serviceMethod = loadServiceMethod(method);
            OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

使用Proxy.newProxyInstance创建了方法接口的一个代理对象,调用接口的方法的时候会进入invoke回调。

在返回这个代理对象之前,其实还有几行代码,我们可以简单看下

  1. 判断接口是否合法,方法数是否>0
    Utils.validateServiceInterface(service)
 static <T> void validateServiceInterface(Class<T> service) {
    if (!service.isInterface()) {
      throw new IllegalArgumentException("API declarations must be interfaces.");
    }
    if (service.getInterfaces().length > 0) {
      throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
    }
  }
  1. 预先加载接口中所有方法
    eagerlyValidateMethods(service);
private void eagerlyValidateMethods(Class<?> service) {
    Platform platform = Platform.get();
    for (Method method : service.getDeclaredMethods()) {
      if (!platform.isDefaultMethod(method)) {
        loadServiceMethod(method);
      }
    }
  }
第三步:调用接口中的方法

由第二步,我们可以知道,其实调用接口的方法,其实最后是调用了刚才创建的代理对象中的方法,然后进入了invoke方法。所以调用的其实是这一段代码。(一般情况下,是调用下面代码,但是也有一些例外,这里就不多介绍了)

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

由于这3行代码是最最关键的部分,这里做详细的分析。

  1. 加载接口方法
    ServiceMethod serviceMethod = loadServiceMethod(method);
ServiceMethod loadServiceMethod(Method method) {
    ServiceMethod result;
    synchronized (serviceMethodCache) {
      result = serviceMethodCache.get(method);
      if (result == null) {
        result = new ServiceMethod.Builder(this, method).build();
        serviceMethodCache.put(method, result);
      }
    }
    return result;
  }

通过反射的Method对象获取一个ServiceMethod对象。

 注意:ServiceMethod: Adapts an invocation of an interface method into an HTTP call

首先会先从cache中获取一个ServiceMethod,如果没有,就创建一个新的ServiceMethod,再存入cache.

前面已经介绍了,就是ServiceMethod可以进行预先加载,默认使用懒加载,就是调用的时候再去加载,如果对方法调用有时间要求,可以使用预先加载,减少一些时间。

下面来看下ServiceMethod的创建

 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一共是2个参数,一个是Retrofit对象,一个是Method对象。

可以看到,这个方法中抛出了很多错误,如果使用过retrofit的人,可以看出,都是一些很常见的错误,大部分是注解用错了。

这里最重要的内容有3点

  1. 创建CallAdapter对象
  2. 创建Converter对象
  3. 对接口方法的注释进行解析

我们一个个来看下:

callAdapter = createCallAdapter();

private CallAdapter<?> 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 {
        return 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(returnType, annotations)

 public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

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

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

    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(adapterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(adapterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

创建CallAdapter主要调用Retrofit中的nextCallAdapter,从adapterFactories中获取一个Factory去创建对应的CallAdapter.如果adapterFactories中所有的Factory都无法创建对应的CallAdapter则会报错。

前面介绍到adapterFactories,其实是可以在构建Retrofit对象的时候传入的。但是我们在前面并未传入CallAdapter.Factory,会不会直接报错呢?不会。

 public Retrofit build() {
     ...
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
      ...
    }
  }

在创建adapterFactories对象时,会预先在里面添加一个默认的CallAdapter.Factory


创建Convert的过程和CallAdapter是一致的,我就不过多介绍了

Builder(Platform platform) {
      this.platform = platform;
      // Add the built-in converter factory first. This prevents overriding its behavior but also
      // ensures correct behavior when using converters that consume all types.
      converterFactories.add(new BuiltInConverters());
    }
...
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
...

这里稍微有点不太一样的地方是,直接在创建Retrofit.Build对象的时候,就先把默认的Convert也就是BuiltInConverters添加到了converterFactories中。


由于Retrofit的注解比较多,所以对接口方法进行解析的过程也比较复杂。也不是整个框架的重点,所以我这里简单介绍下,其中有些地方还是值得我们去学习的。

解析注释,一共分2部分,一个是解析方法上的注释,一个是解析参数上的注释。

 public ServiceMethod build() {
      ...
      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation);
      }

      ...
      for (int p = 0; p < parameterCount; p++) {
        ...
        parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
      }
      ...
      return new ServiceMethod<>(this);
    }
  1. 方法上的注释:
    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;
      }
    }

方法上的注释,确实是没啥好说的,就是判断不同的注解进行不同的解析,然后给自己的一些当前变量赋值。我就不说了。

  1. 方法参数上的注释
    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;
    }

我就不再深入了,简单点说就是把参数上的注释转化为ParameterHandler对象。来看下ParameterHandler对象是啥。

abstract class ParameterHandler<T> {
  abstract void apply(RequestBuilder builder, T value) throws IOException;
  final ParameterHandler<Iterable<T>> iterable() {
    return new ParameterHandler<Iterable<T>>() {
      @Override void apply(RequestBuilder builder, Iterable<T> values) throws IOException {
     ...
    };
  }

  final ParameterHandler<Object> array() {
    return new ParameterHandler<Object>() {
      @Override void apply(RequestBuilder builder, Object values) throws IOException {
       ...
      }
    };
  }

  static final class RelativeUrl extends ParameterHandler<Object> {
    @Override void apply(RequestBuilder builder, Object value) {
      builder.setRelativeUrl(value);
    }
  }

  static final class Header<T> extends ParameterHandler<T> {
    ...
  }

  static final class Path<T> extends ParameterHandler<T> {
    ...
  }

  static final class Query<T> extends ParameterHandler<T> {
   ...
  }

  static final class QueryMap<T> extends ParameterHandler<Map<String, T>> {
    ...
  }

  static final class Field<T> extends ParameterHandler<T> {
  ...
  }

  static final class FieldMap<T> extends ParameterHandler<Map<String, T>> {
    ...
  }

  static final class Part<T> extends ParameterHandler<T> {
    ...
  }

  static final class RawPart extends ParameterHandler<MultipartBody.Part> {
   ...
  }

  static final class PartMap<T> extends ParameterHandler<Map<String, T>> {
   ...
  }

  static final class Body<T> extends ParameterHandler<T> {
    ...
}

所有的注解对应的都有自己的一个ParameterHandler实现。然后在里面进行解析。

解析方法注释得到的参数,以及解析方法参数的注释得到的ParameterHandler都是为了构建Request对象,代码如下:

 Request toRequest(Object... args) throws IOException {
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    @SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
    ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;

    int argumentCount = args != null ? args.length : 0;
    if (argumentCount != handlers.length) {
      throw new IllegalArgumentException("Argument count (" + argumentCount
          + ") doesn't match expected count (" + handlers.length + ")");
    }

    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }

    return requestBuilder.build();
  }

其中handlers[p].apply(requestBuilder, args[p]);是循环调用ParameterHandler这个抽象类的抽象方法。这里是值得我们学习的,依赖抽象类和接口,而不依赖具体的实现。

下面我们可以再回过头来看
/** Adapts an invocation of an interface method into an HTTP call. */
官方对ServiceMethod的说明。
其实就我个人理解,是不是改成
/** Adapts an invocation of an interface method into an HTTP request. */
会更好点,因为ServiceMethod是把接口方法最终转化为一个Request对象而不是一个Call对象,当然也只是个人的理解。


  1. 创建OkHttpCall对象
    OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
 OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
    this.serviceMethod = serviceMethod;
    this.args = args;
  }

OkHttpCall的构造方法很简单,OkHttpCall实现了Call接口。

  1. CallAdapter对Call对象进行转换

在介绍这个之前,我们再回顾下前面的默认的CallAdapter。
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

这里需要了解Platform

class Platform {
 ..
  }
  static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      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);
      }
    }
  }

  static class IOS extends Platform {
    ...
  }
}

对不同的平台进行不同的处理。这里肯定是Android平台,所以应该调用Android中的方法。

所以,默认的CallAdapter.FactoryExecutorCallAdapterFactory
下面我们继续刚才最重要的3句代码中的最后一句代码
return serviceMethod.callAdapter.adapt(okHttpCall);

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

      @Override public <R> Call<R> adapt(Call<R> call) {
        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) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

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

使用adapt方法后,返回了ExecutorCallbackCall这个对象

第四步:enqueue发送请求(execute大同小异)

具体的代码请看上面,从ExecutorCallbackCall开始。
前面一步步走下来,我们已经知道,调用接口方法后,真正返回的是ExecutorCallbackCall对象。

调用enqueue方法,其实是调用创建ExecutorCallbackCall对象时传入的Call对象。我们在前面第三步时解析了最关键的三句代码,了解到了其实这里的Call对象,就是OkHttpCall对象。

@Override public void enqueue(final Callback<T> callback) {
    ...
    call = rawCall = createRawCall();
    ...
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
          ...
          response = parseResponse(rawResponse);
         ...
    });
  }
...
private okhttp3.Call createRawCall() throws IOException {
    Request request = serviceMethod.toRequest(args);
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }
...
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
     ...
      T body = serviceMethod.toResponse(catchingBody);
      return Response.success(body, rawResponse);
     ...
  }

其中最重要的2个方法就是

  1. createRawCall
  2. parseResponse

这里我们分别来分析下。


createRawCall
这里主要调用了serviceMethod.toRequest(args)其实我们在前面已经介绍过了,ServiceMethod中的toRequest就是把前面解析完成的参数,转化为对应的Request,这里就不多说了。

这里我们还要了解serviceMethod.callFactory是什么?
ServiceMethod.java

...
 ServiceMethod(Builder<T> builder) {
    this.callFactory = builder.retrofit.callFactory();
     ...
  }

Retrofit.java

...
 public Builder client(OkHttpClient client) {
      return callFactory(checkNotNull(client, "client == null"));
    }

    /**
     * Specify a custom call factory for creating {@link Call} instances.
     * <p>
     * Note: Calling {@link #client} automatically sets this value.
     */
    public Builder callFactory(okhttp3.Call.Factory factory) {
      this.callFactory = checkNotNull(factory, "factory == null");
      return this;
    }
...
 public Retrofit build() {
      ...
      okhttp3.Call.Factory callFactory = this.callFactory;
      if (callFactory == null) {
        callFactory = new OkHttpClient();
      }
      ...
...

由上代码可看出,ServiceMethod中的callFactory就是Retrofit中的callFactory,可以在构建Retrofit对象的时候传入,不传入默认为OkHttpClient

所以
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
这里的serviceMethod.callFactory其实就是OkHttpClient然后创建了一个Call对象。真正发起请求的也是这个Call对象。

这里可能会看起来有点糊涂,因为这里的Callokhttp3.Call,而前面一直在说的Callretrofit2.Call大家不要把这2个搞混了。

我们可以把这2个做一下对比会发现,它们的方法基本一致。

Retrofit我们可以理解为在okhttp3外面的一层封装,真正去发生http请求的还是原来的okhttp3


parseResponse
代码在上面已贴出,其中最重要的一句是:
T body = serviceMethod.toResponse(catchingBody);

...
this.responseConverter = builder.responseConverter;
...
T toResponse(ResponseBody body) throws IOException {
    return responseConverter.convert(body);
  }
...

使用Convert对象把ResponseBody转化为另一个对象。由代码可以看出,ServiceMethod中的responseConverter也是来自Retrofit对象。也就是前面介绍的默认的Convert.Factory对象,也就是BuiltInConverters,产生的Convert对象。

final class BuiltInConverters extends Converter.Factory {
  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    if (type == ResponseBody.class) {
      if (Utils.isAnnotationPresent(annotations, Streaming.class)) {
        return StreamingResponseBodyConverter.INSTANCE;
      }
      return BufferingResponseBodyConverter.INSTANCE;
    }
    if (type == Void.class) {
      return VoidResponseBodyConverter.INSTANCE;
    }
    return null;
  }

ServiceMethod中会根据方法的返回类型,在里面获取到对应的Convert对象。如果返回的类型没有相应的Convert则会返回null。
Retrofit.java

 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 =
        //**在这里真正去获取对应的Convert**
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

    StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
        .append(type)
        .append(".\n");
    if (skipPast != null) {
      builder.append("  Skipped:");
      for (int i = 0; i < start; i++) {
        builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
      }
      builder.append('\n');
    }
    builder.append("  Tried:");
    for (int i = start, count = converterFactories.size(); i < count; i++) {
      builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
    }
    throw new IllegalArgumentException(builder.toString());
  }

从代码中可以看出,如果返回为null,那么会从下一个Convert.Factory中去获取对应的Convert由于我们前面并未添加Convert.Factory,所以这里只有一个默认的BuiltInConverters,并且它只支持返回值是ResponseBody,Void这2种类型的或者注释中有Streaming的方法,否者会报错。

第五步:在Callback接口中对转换后的对象进行处理

到了这一步的时候其实源码代码已经分析的差不多了。但是前面提到的默认的
CallAdapter.Factory也就是ExecutorCallAdapterFactory中其实有个细节刚才我没有细讲,现在可以回过去看。

 @Override public void enqueue(final Callback<T> callback) {
      if (callback == null) throw new NullPointerException("callback == null");

      delegate.enqueue(new Callback<T>() {
        @Override public void onResponse(Call<T> call, final Response<T> response) {
        //**使用callbackExecutor去执行真正的callback中的onResponse和onFailure**
          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);
            }
          });
        }
      });

我们往回追溯,看下callbackExecutor是什么

static class Android extends Platform {
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    @Override CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
      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);
      }
    }
  }

defaultCallbackExecutor其实就是把Runnable抛到主线程中去执行。
所以在我们自己的Callback中的onResponseonFailure已经都是在主线程中执行了。

总结

Retrofit的源码相对来说是比较少的,非常适合新手阅读(包括我),可以快速体验阅读源码的乐趣,感觉对整个框架的使用都会得心应手。

另外自己也感受到了阅读源码的3个好方法。

  1. 先了解所有的接口,对整个框架有个大致的了解
  2. 可以写一个简单的demo,一步步深入
  3. 从后往前,想要知道一个变量的由来,可以往前追溯
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容