Retrofit源码解析

一,前言

Retrofit其实是将OKhttp封装起来,和volley一样。那解析Retrofit其实就是解析它如何封装使用OKhttp,那我直接从其使用上来跟踪源码。

总体上可以分为四步:

  1. 创建Retrofit对象
  2. 通过Retrofit获取接口对象
  3. 通过接口对象获取请求服务的Call对象
  4. 最后通过Call的异步enqueue或同步execute来执行网络请求并回调结果。

下面也是通过这四步来解析源码

二,创建Retrofit对象

先占时不考虑RxJava的使用

Retrofit retrofit = new Retrofit.Builder()  //1
    .baseUrl(baseUrl)   //2
    .addConverterFactory(GsonConverterFactory.create()) //3
    .build();   //4

Retrofit是通过建造者模式来构建对象的,那很明显,这里只是配置了请求网络的参数而已,而这些配置在后面的网络请求和结果转换用到了。

第二步是为了配置请求服务的地址;第三部是配置返回结果的转换器,使结果为对象。

2.1 Builder()

public static final class Builder {
    private final Platform platform;
    // 网络请求器的工厂
    private @Nullable okhttp3.Call.Factory callFactory;
    // 网络请求的url地址
    private HttpUrl baseUrl;
    // 数据转换器工厂的集合,生产数据转换器(converter)
    private final List<Converter.Factory> converterFactories = new ArrayList<>();
    // 网络请求适配器工厂的集合,生产网络请求适配器(CallAdapter)
    private final List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
    //// 请求结束后回调方法的执行Executor
    private @Nullable Executor callbackExecutor;
    // 是否提前对业务接口中的注解进行验证转换的标志位
    private boolean validateEagerly;
    
    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());
    }
    
    public Builder() {
      this(Platform.get());
    }
    ...
}

Builder里存储的参数都会在Retrofit创建时赋值给它,后面的build()再介绍。

在创建Builder()对象时,其实只赋值了两个属性:platform 和converterFactories。可以知道默认的请求结果转换器为BuiltInConverters,我们开发中一般使用GsonConverterFactory.create()。

2.1.1 Platform

Platform是单例模式,通过Platform.get()来获取对象。

class Platform {
  //单例对象是通过findPlatform()创建的
  private static final Platform PLATFORM = findPlatform();

  static Platform get() {
    return PLATFORM;
  }

  private static Platform findPlatform() {
    try {
      //如果是安卓系统,就返回Android()
      Class.forName("android.os.Build");
      if (Build.VERSION.SDK_INT != 0) {
        return new Android();
      }
    } catch (ClassNotFoundException ignored) {
    }
    try {
     // Java8()
      Class.forName("java.util.Optional");
      return new Java8();
    } catch (ClassNotFoundException ignored) {
    }
    return new Platform();
  }
  
  static class Android extends Platform {
    //请求结果回调使用的Executor,如果Builder没有赋值给callbackExecutor,就会调用这个方法赋值
    @Override public Executor defaultCallbackExecutor() {
      return new MainThreadExecutor();
    }

    //Builder里的CallAdapter.Factory,最后会在build()里赋值给adapterFactories,作为默认的网络请求适配器
    @Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
      if (callbackExecutor == null) throw new AssertionError();
      //那可以看出默认的网络适配器是ExecutorCallAdapterFactory实现的
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }

    //调用handler使回调在主线程执行
    static class MainThreadExecutor implements Executor {
      private final Handler handler = new Handler(Looper.getMainLooper());

      @Override public void execute(Runnable r) {
        handler.post(r);
      }
    }
  }
}

最为安卓平台,Platform最终赋值的对象是静态内部类Android,这个对象作为默认配置,会在Builder的build()方法中调用赋值。

defaultCallbackExecutor是返回回调执行的Executor,返回的MainThreadExecutor是使用handler让回调操作在主线程执行。如果在Builder中没有指定回调的Executor,会调用defaultCallbackExecutor指定异步网络请求的回调在主线程执行

defaultCallAdapterFactory则是指定默认网络适配器工厂为ExecutorCallAdapterFactory,调用接口方法返回的Call,就是这个类创建的。具体等后面使用其功能再介绍。

2.2 其它配置

2.2.1 baseUrl

就是将String类型的url,经过合格性检测,拆分存储,再转换成HttpUrl赋值给baseUrl。

public Builder baseUrl(String baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  //将String的转为HttpUrl
  HttpUrl httpUrl = HttpUrl.parse(baseUrl);
  if (httpUrl == null) {
    throw new IllegalArgumentException("Illegal URL: " + baseUrl);
  }
  return baseUrl(httpUrl);
}
public Builder baseUrl(HttpUrl baseUrl) {
  checkNotNull(baseUrl, "baseUrl == null");
  List<String> pathSegments = baseUrl.pathSegments();
  //如果路径结尾不是以"/"结尾,会抛出异常
  if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
    throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
  }
  this.baseUrl = baseUrl;
  return this;
}

值得注意的是,路径必须以"/"结尾

2.2.2 addConverterFactory

//将转换工厂保存到converterFactories中,在构造器中,已经add了一个BuiltInConverters
public Builder addConverterFactory(Converter.Factory factory) {
  converterFactories.add(checkNotNull(factory, "factory == null"));
  return this;
}

上面的例子是添加GsonConverterFactory,下面来看看它是如何转换的。

2.2.2.1 GsonConverterFactory

public final class GsonConverterFactory extends Converter.Factory {

  @Override
  public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
      Retrofit retrofit) {
    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
    //返回对应的Converter对象
    return new GsonResponseBodyConverter<>(gson, adapter);
  }
}

final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {

    @Override public T convert(ResponseBody value) throws IOException {
    JsonReader jsonReader = gson.newJsonReader(value.charStream());
    try {
      //将ResponseBody转为泛型对象
      return adapter.read(jsonReader);
    } finally {
      value.close();
    }
  }

通过convert转换的类型,是在调用responseBodyConverter创建对象时传入的请求接口的返回类的泛型。也就是例子中的HttpResult。

如果要自定义Converter来实现请求结果转化,按上面那样就可以了,使用工厂方法模式

  1. 继承Converter,在convert方法中返回转换后的结果,比如GsonRequestBodyConverter中是把ResponseBody转成自己需要转的类型。
  2. 继承Converter.Factory,在responseBodyConverter中将相应的Converter对象返回。
  3. 在Retrofit的创造器中调用addConverterFactory添加相应的Converter.Factory。

2.3 build()

这部将根据先前的配置生成Retrofit,其实Builder中的配置属性几乎都赋值给了Retrofit。

public Retrofit build() {

    //callFactory是类okhttp3.Call.Factory的对象,如果自己没有设置了OkHttp对象,则会自己创建一个。
  okhttp3.Call.Factory callFactory = this.callFactory;
  if (callFactory == null) {
    callFactory = new OkHttpClient();
  }

  //回调方法执行器
  Executor callbackExecutor = this.callbackExecutor;
  //没有指定的话,就用构造器中赋值的platform中的,也就是将回调放在主线程
  if (callbackExecutor == null) {
    callbackExecutor = platform.defaultCallbackExecutor();
  }

  // 将配置的网络适配器进行保护性拷贝
  List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
  //添加默认的网络适配器,也就是ExecutorCallAdapterFactory
  adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

  // 与网络适配器的排序不同,默认的BuiltInConverters放在第一位,后面才是添加的
  List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

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

对于网络适配器队列存储顺序和数据转化器的队列顺序不同,其实是在后面给ServiceMethod赋值相应属性时,采取了不同的取值策略。网络适配器优先获取队列前面的;数据转化器虽然也是从队列前面开始适配,但默认的BuiltInConverters要接口返回类型为ResponseBody或Void才会返回Converter对象,返回类型为其它时,会继续遍历后面的数据转化器,所以在设定返回值为对象时,GsonConverterFactory会起作用。具体后面ServiceMethod创建时会介绍。

2.4 总结

在最后build()中,可以发现创建Retrofit时,传入了6个参数。

  1. OKHttp对象。比如设置连接超时时间的OKHttp
  2. 服务器地址。必填
  3. 请求结果的数据转换器。对于请求结果的返回类型进行转换
  4. 网络适配器。默认为ExecutorCallAdapterFactory,通常设置为RxJava2CallAdapterFactory.create()。
  5. 回调方法执行器。默认回调在主线程执行。
  6. 是否提前对业务接口中的注解进行验证转换的标志位。在create中有用到。

比较重要的类有设置默认回调方法执行器和默认网络适配器的Platform;默认的数据转换器BuiltInConverters。

三 通过Retrofit获取接口对象

MovieService movieService = retrofit.create(MovieService.class);

public interface MovieService {
    //get请求
    @GET("top250")
    //网络请求数据的方法,@Query配置请求参数
    Call<HttpResult<List<Subject>>> getTopMovie(@Query("start")int start, @Query("count")int count);
}

MovieService是个接口,里面定义了一个方法,通过注解上面配置了请求接口的参数配置,retrofit通过方法的参数创建接口对象。

那来看看如何通过接口来获取对象。

3.1 create

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    //是否提前通过注解加验证加载请求接口,会将接口中的方法都解析成ServiceMethod,并加入serviceMethodCache缓存中
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    //创建动态代理对象,用来代理接口
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
    new InvocationHandler() {   //将代理类的实现交给 InvocationHandler类作为具体的实现
      private final Platform platform = Platform.get();

      //被代理执行的方法,是通过在InvocationHandler中的invoke方法调用的
      @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
          throws Throwable {
        // Object的方法直接调用原方法
        if (method.getDeclaringClass() == Object.class) {
          return method.invoke(this, args);
        }
        //android默认为false,不走
        if (platform.isDefaultMethod(method)) {
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }
        
        //这里才是被代理方法真正执行的地方
        //通过接口方法的注解来获取ServiceMethod
        ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        //如果是默认网络适配器,就生成Call对象;RxJava则生成Observable对象
        return serviceMethod.callAdapter.adapt(okHttpCall);
      }
    });
}

代理模式的动态代理是实现接口方法调用的关键,动态代理也只能代理接口,invoke方法是接口方法正在实现的地方,生成的代理对象在运行时存在内存中。

这样

那接下来看接口方法的调用。

四 通过接口对象获取请求服务的Call对象

Call<HttpResult<List<Subject>>> call = movieService.getTopMovie(0, 10);

这里的getTopMovie方法调用,是在上面invoke方法中实现的,主要是这几行代码

//通过方法注解配置,获取ServiceMethod
ServiceMethod<Object, Object> serviceMethod =
    (ServiceMethod<Object, Object>) loadServiceMethod(method);
//根据ServiceMethod创建OkHttpCall
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
//创建Call
return serviceMethod.callAdapter.adapt(okHttpCall);

4.1 loadServiceMethod

ServiceMethod<?, ?> loadServiceMethod(Method method) {
    //从缓存中获取,如果先前创建过久直接用
    //create中的eagerlyValidateMethods方法会提前创建对象并缓存
    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;
  }

对象的创建是通过new ServiceMethod.Builder<>(this, method).build()实现的。

4.1.1 new ServiceMethod.Builder<>(this, method)

Builder(Retrofit retrofit, Method method) {
  this.retrofit = retrofit;
  this.method = method;
  //获取方法里的注解
  this.methodAnnotations = method.getAnnotations();
  //获取方法的参数类型
  this.parameterTypes = method.getGenericParameterTypes();
  //获取方法参数里的注解
  this.parameterAnnotationsArray = method.getParameterAnnotations();
}

就是赋值。

4.1.2 build()

public ServiceMethod build() {
    //1.根据接口的返回类型和注解,从retrofit中获取网络适配器
    callAdapter = createCallAdapter();
    //方法返回值泛型的类型,也就是网络请求的返回值类型
    responseType = callAdapter.responseType();
    
    //2.根据方法的返回类型和注解,网络数据转换器
    responseConverter = createResponseConverter();
    
    //3.获取方法上的注解
    for (Annotation annotation : methodAnnotations) {
      //根据注解获取配置
      parseMethodAnnotation(annotation);
    }
    
    //4.获取方法参数里的注解
    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);
    }
    
    return new ServiceMethod<>(this);
}

重点关注下网络适配器和数据转换器是如何获得的,根据前面的Builder可知,retrofit里它们都是以数组保存的,那获取规则又如何呢。

4.1.2.1 createCallAdapter

先看网络适配器如何获取的。

private CallAdapter<T, R> createCallAdapter() {
    //返回值类型
  Type returnType = method.getGenericReturnType();
  //方法注解
  Annotation[] annotations = method.getAnnotations();
  try {
    //通过retrofit的callAdapter方法返回的
    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);
  }
}

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

public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      //从0开始
    int start = adapterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      //在分析的例子中,没有配置网络适配器,所以用的默认的ExecutorCallAdapterFactory
      //使用RxJava会配置了RxJava2CallAdapterFactory
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }
}

因为例子没有配置网络适配器
这里是使用默认的网络适配器ExecutorCallAdapterFactory,如果配置了RxJava2CallAdapterFactory,它会在默认网络适配器的前面,那时就会使用RxJava2CallAdapterFactory了。ExecutorCallAdapterFactory这个到后面通过网络适配器返回的Call调用enqueue时再介绍。

4.1.2.2 createResponseConverter

解析的例子中,是配置了GsonConverterFactory数据转换器。和上面的网络适配器一样,数据转换器也是从retrofit保存的配置信息中获取的

public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
      @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
    //从0开始
    int start = converterFactories.indexOf(skipPast) + 1;
    for (int i = start, count = converterFactories.size(); i < count; i++) {
    //默认的数据转换器BuiltInConverters,如果接口方法返回值类型不是ResponseBody和Void的话,返回null
    //分析的这个例子中,接口方法返回值的泛型是HttpResult,所以会循环到下个GsonConverterFactor对象
      Converter<ResponseBody, ?> converter =
          converterFactories.get(i).responseBodyConverter(type, annotations, this);
      if (converter != null) {
        //noinspection unchecked
        return (Converter<ResponseBody, T>) converter;
      }
    }

  }

数据转换器把默认的BuiltInConverters放在了第一位,但还是根据接口方法返回值泛型会过滤选择。所以在自定义转换器时,要过滤要转换的类型

4.2 ExecutorCallAdapterFactory

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

又回到Retrofit中create的动态代理中来,到invoke中最后一步,返回Call。(如果是RxJava,则返回Observable)

根据上面的分析,可以知道serviceMethod.callAdapter对象是默认的ExecutorCallAdapterFactory。callAdapter和Converter都采用了工厂方法模式来实现,理解这个更有助于自定义它们。

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) {
    //返回值类型判断,要是Call才行
    if (getRawType(returnType) != Call.class) {
      return null;
    }
    //返回值泛型的类型,如例子中的HttpResult
    final Type responseType = Utils.getCallResponseType(returnType);
    //返回CallAdapter
    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        //相应的call对象
        return new ExecutorCallbackCall<>(callbackExecutor, call);
      }
    };

  }
}

CallAdapter和它的工厂CallAdapter.Factory,是自定义CallAdapter的关键。

  • CallAdapter的adapt方法返回接口方法的返回值,上面是返回Call对象。如果是RxJava,则返回Observable对象。
  • CallAdapter.Factory则是创建CallAdapter的工厂,它的get方法返回CallAdapter对象
  • CallAdapter的adapt方法的返回对象,是实现后续网络请求的关键,自定义要在返回对象中将自己封装的网络请求放在里面。

4.3 总结

到这里,如何通过接口对象调用方法获取Call已经很明了了。就是通过动态代理对象里的InvocationHandler里的invoke方法实现,调用接口对象方法实际上是调用invoke方法。

在invoke中,首先根据接口方法的注解和Retrofit里的配置通过建造者模式生成ServiceMethod对象,再生成实现网络请求的对象OkHttpCall,通过ServiceMethod中的CallAdapter来生成封装了OkHttpCall的Call对象(RxJava则是Observable)。

自定义CallAdapter的关键是实现CallAdapter和CallAdapter.Factory。

五 请求网络

请求网络时通过调用call.enqueue,那来看看默认的Call对象相应方法的实现,也就是ExecutorCallAdapterFactory里的ExecutorCallbackCall

static final class ExecutorCallbackCall<T> implements Call<T> {
    //回调方法执行器
    final Executor callbackExecutor;
    //OkHttpCall对象,是生成ExecutorCallbackCall时传入的
    final Call<T> delegate;

//在CallAdapter的adapt方法中被创建赋值
    ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
      this.callbackExecutor = callbackExecutor;
      this.delegate = delegate;
    }

    @Override public void enqueue(final Callback<T> callback) {
      checkNotNull(callback, "callback == null");
    
    //代理模式,最终还是OkHttpCall实现
      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()) {
              //失败回调
               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);
            }
          });
        }
      });
    }
  }

ExecutorCallbackCall用的代理模式,最终实现的对象的OkHttpCall。

OkHttp的使用就分四步

  1. 创建okHttpClient对象
  2. 创建一个Request
  3. new call
  4. 请求加入调度

真正实现网络请求的就是OKHttp,我们可以从上面四步了解网络请求的实现。第一步在创建retrofit对象时就已经完成了。

5.1 OkHttpCall

OkHttpCall是retrofit2中封装的一个类,内部调用还是通过ServiceMethod获取网络请求配置并生成okhttp3.Call来实现。

@Override public void enqueue(final Callback<T> callback) {
    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 {
        //1.生成okhttp3.Call对象,默认是OkHttpClient的newCall创建,为RealCall对象
          call = rawCall = createRawCall();
        } catch (Throwable t) {
          failure = creationFailure = t;
        }
      }
    }
    //2.发送异步网络请求
    call.enqueue(new okhttp3.Callback() {
      @Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
          throws IOException {
        Response<T> response;
        try {
        //3.通过存在serviceMethod的Converter转换数据类型
          response = parseResponse(rawResponse);
        } catch (Throwable e) {
          callFailure(e);
          return;
        }
        //4.回调接口
        callSuccess(response);
      }

      @Override public void onFailure(okhttp3.Call call, IOException e) {
        try {
          callback.onFailure(OkHttpCall.this, e);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }

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

      private void callSuccess(Response<T> response) {
        try {
          callback.onResponse(OkHttpCall.this, response);
        } catch (Throwable t) {
          t.printStackTrace();
        }
      }
    });
  }

可以看出实现网络请求的是OKhttp,那只要关注okhttp3.Call是如何创建和网络请求结果如何转换就好了。

5.1.1 createRawCall()

okhttp3.Call的创建就完成了OkHttp使用的前三步了,下面来看看前三部是怎么实现的吧。

所有的网络配置信息都在ServiceMethod中,很明显,它们的生成也都在ServiceMethod中,通过默认的OkHttpClient的newCall创建,为RealCall对象,这些还是后面看OKHttp的解析了解吧。

private okhttp3.Call createRawCall() throws IOException {
    //创建Request对象,将请求网络的信息都封装在里面
    Request request = serviceMethod.toRequest(args);
    //callFactory是okhttp3.Call.Factory,在创建Retrofit时默认的OkHttpClient
    //正常OKhttp生成Call的流程
    okhttp3.Call call = serviceMethod.callFactory.newCall(request);
    if (call == null) {
      throw new NullPointerException("Call.Factory returned null.");
    }
    return call;
  }

创建Request,再创建okhttp3.Call,这是正常的OkHttp请求的第二三步。这里只关心Retrofit的封装,就看toRequest方法了。

5.1.1.1 serviceMethod.toRequest

Request toRequest(@Nullable Object... args) throws IOException {
    //创造者模式构建对象
    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
        contentType, hasBody, isFormEncoded, isMultipart);

    //接口方法的参数的注解结合
    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 + ")");
    }
    //对接口方法参数,会在apply中转换参数类型,并添加到requestBuilder中。
    //数据转换默认使用BuiltInConverters.ToStringConverter.INSTANCE,也就是直接将参数值toString()
    for (int p = 0; p < argumentCount; p++) {
      handlers[p].apply(requestBuilder, args[p]);
    }
    //里面通过参数,用普通的OKhttp的建造器生成Request
    return requestBuilder.build();
  }
  
  //例子中,添加的请求参数是Query,所以上面handlers[p].apply的实现是
  static final class Query<T> extends ParameterHandler<T> {

    @Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
      if (value == null) return; // Skip null values.
    //这里就是把value.toString()了
      String queryValue = valueConverter.convert(value);
      if (queryValue == null) return; // Skip converted but null values
    //添加到请求url里去
      builder.addQueryParam(name, queryValue, encoded);
    }
  }

对于接口方法注解的解析,我就不做太多介绍了。handlers[p].apply是将方法参数的配置信息添加到requestBuilder中去,将参数配置都添加后,在build中,用OKhttp的Request.Builder生成Request对象。

RequestBuilder将baseUrl和请求接口方法里的注解配置信息组合起来,将配置信息添加入Request.Builder中,创建Request。

5.2 parseResponse

call.enqueue这个方法是okhttp3.Call的方法,就不分析了,主要分析请求服务结束后,将数据类型转换为回调接口需要的类型。

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

    // 移除Response中的响应正文,在此基础上创建一个新的Response
    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);
      //将转换后内容和空body的Response再组合成Retrofit里的Response
      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;
    }
  }

这里将okhttp3.Response,将响应正文通过数据转换器转换,再和空响应正文的okhttp3.Response组合成Retrofit里的Response,用于回调使用。

callback.onResponse是回调了默认网络适配器里的ExecutorCallbackCall里的Callback,然后ExecutorCallbackCall里再使用默认的Executor在主线程回调例子里的Callback。

六 总结

  1. Converter和CallAdapter都是用工厂方法模式实现的,自定义时要分别实现产品类和工厂类,在工厂类中创建产品。
  2. Retrofit是通过建造者模式创建的,Retrofit.Builder()主要配置:网络请求工厂(okhttp3.Call.Factory),网络请求地址(HttpUrl),数据转换器(List<Converter.Factory>),网络适配器(List<CallAdapter.Factory>),回调执行方法(Executor),是否提前对业务接口中的注解进行验证转换的标志位(validateEagerly)
  3. 接口方法里通过注解配置了网络请求的配置,通过Retrofit的create方法,动态代理实现了接口方法。接口方法的返回值是网络适配器返回对象,类型要和接口方法的返回值一致。
  4. 动态代理的invoke方法里,通过Retrofit的配置和接口方法的注解配置生成ServiceMethod对象,这个对象保存了网络请求的所有配置。大部分方法和解析注解生成配置有关,主要关注两个方法:一个toRequest通过RequestBuilder生成OKhttp的Request,toResponse可以利用数据转换器将ResponseBody转为请求接口方法返回值泛型。这两个方法都是给OkHttpCall使用。
  5. 再通过ServiceMethod创建了OkHttpCall,里面有请求网络的方法,实际上是根据ServiceMethod的配置网络信息生成的Request再生成okhttp3.Call,将请求结果通过ServiceMethod的配置转换器进行数据转换,最终回调给调用它的类(默认ExecutorCallbackCall)。
  6. ExecutorCallAdapterFactory是默认的网络适配器工厂,在动态代理的invoke方法里,创建ServiceMethod时用get方法生成适配器后,再通过适配器的adapt生成ExecutorCallbackCall返回值,ExecutorCallbackCall中用静态代理模式实现,被代理对象是OkHttpCall。
  7. GsonConverterFactory的具体转换结果类型,是在创建ServiceMethod时,用解析的接口方法中的返回值泛型确定的。
  8. 随后再列下关键的几个类:
  • Retrofit:用创建者模式存储网络配置。
  • ServiceMethod:通过接口方法注解的配置和Retrofit里的配置,生成ServiceMethod。toReques和toResponse方法供给OkHttpCall使用。
  • ServiceMethod中利用RequestBuilder,生成Request请求。Request利用Retrofit配置的网络参数,和ServiceMethod里解析接口方法里的注解配置,生成Request请。
  • OkHttpCall:网络请求的封装类,内部结合ServiceMethod的toReques生成OKHttp实现网络请求,再用ServiceMethod的toResponse转换结果回调给调用它的对象,这个对象是网络适配器adapt生成。

参考

Android OkHttp完全解析 是时候来了解OkHttp了

你真的会用Retrofit2吗?Retrofit2完全教程

Android:手把手带你 深入读懂 Retrofit 2.0 源码

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

推荐阅读更多精彩内容