Retrofit源码解析

来源:互联网 发布:外置光驱盒 mac 编辑:程序博客网 时间:2024/04/30 09:08

Retrofit源码结构

Retrofit: 通过注解,把一个Java接口转化成一个http 请求,底层网络请求基于okhttp

从Retrofit源码结构可以看出,Retrofit 源码分成两部分
这里写图片描述

一部分是包retrofit2.http里面的,在Java接口方法中使用,用来控制http行为的注解。

一部分是retrofit2里面的,负责把REST API转化成Java接口。

Retrofit和okhttp的关系

retrofit依赖okhttp库,retrofit 所有的网络请求都是由okhttp处理,可以说retrofit是对okhttp封装了,让其使用更加简单方便。
okhttp 准确来说是一个Java库,没有Android中主线程和工作线程的概念,Android有两个限制,第一不能再主线程中直接请求网络,第二不能在工作线程中直接更新UI,所以,如果我们在Android中直接使用okhttp,需要用到Handler来传递请求结果。而如果使用retrofit,则不需要我们去创建线程执行网络请求,也不需要使用Handler把请求结果从工作线程传递到主线程。retrofit直接在主线程中发起异步请求,最后收到请求结果也是在主线程中,非常方便。

主要类和方法

Retrofit:retrofit框架的入口类,主要有两个功能:
1、通过内部类Builder配置构建Retrofit实例。Builder主要配置选项:

1. client(OkHttpClient client) :设置一个配置好的OkHttpClient实例,不配置的话retrofit会默认new一个。2. baseUrl(String baseUrl) :设置API地址。3. addConverterFactory(Converter.Factory factory) :设置一个数据转化工厂,比如把Json和实体类之间的转化。4. addCallAdapterFactory(CallAdapter.Factory factory):设置一个适配器工厂,方便和其他库配合使用,如RxJava。

另外,如果我们没有设置执行任务的线程池的话,Retrofit会根据不同的平台,得到默认的线程池。

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

Android 中默认的线程池:

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

从上面代码可以看到,先会创建一个在主线程中的Handler,然后默认线程池执行的任务都是在Android的主线程中执行的,这也是在Retrofit异步回调中我们能直接在里面更新UI的原因。

另外,Retrofit根据不同使用平台,会默认添加一个CallAdapterFactory

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

Android 中添加的是ExecutorCallAdapterFactory:

2、通过Retrofit的create方法,实现描述http请求的Java接口。

// Create an instance of our GitHub API interface.GitHub github = retrofit.create(GitHub.class);// Create a call instance for looking up Retrofit contributors.Call<List<Contributor>> call = github.contributors("square", "retrofit");

我们在使用Retrofit时,首先要通过Retrofit实例来得到一个请求接口的实例(github),然后调用这个实例的一个方法(contributors)构造一个Call对象。这个过程主要是Retrofit的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);        }      });}

当调用接口里面方法的时候(github.contributors(“square”, “retrofit”) ),会执行InvocationHandler里面的内容,通过反射,得到调用的method相关信息,然后构造ServiceMethod和OkHttpCall的实例,在Android中通过ExecutorCallAdapterFactory 把 OkHttpCall 进行转换 ExecutorCallbackCall:

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

最后我们得到的Call对象实际上是ExecutorCallbackCall实例。得到Call实例之后,就可以通过call.enqueue进行网络请求,我们看看ExecutorCallbackCall中的enqueue方法:

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

在ExecutorCallbackCall中的enqueue里面,又调用delegate.enqueue方法,这个delegate,其实是OkHttpCall对象,也就是调用OkHttpCall中的enqueue方法。
首先构造一个okhttp中的Request对象:

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

可以看出,是通过ServiceMethod的toRequest方法得到的:

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

其中构造RequestBuilder的参数都是ServiceMethod 从Java接口中的注解解析出来的。

ServiceMethod: 从这个类的方法结构可以看出,这个类主要作用是把方法的注解解析成变量保存起来。

这里写图片描述

1 0