Retrofit 源码分析

来源:互联网 发布:创意视频制作软件 编辑:程序博客网 时间:2024/05/22 17:48

我在半年前才开始接触 Retrofit,在那个时候这个框架已经很火了。现在寒假复习到这一块,也好久没写博客了,简单梳理了一下写成一篇文章。有不对的地方,望指正。

好,开始进攻。

Retrofit 的创建

使用 Retrofit 的时候,首先通过建造者模式来创建 Retrofit 对象,创建姿势是这样的:

Retrofit retrofit = new Retrofit.Builder()        .baseUrl("https://api.github.com")        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())        .addConverterFactory(GsonConverterFactory.create())        .build();

先看到 Builder 的构造方法,

public Builder() {  this(Platform.get());}
private static final Platform PLATFORM = findPlatform();static Platform get() {  return PLATFORM;}

获取运行的平台,至于怎么获取?通过 Class.forName() 的方式来查找。如下:

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) {  }  try {    Class.forName("org.robovm.apple.foundation.NSObject");    return new IOS();  } catch (ClassNotFoundException ignored) {  }  return new Platform();}

有三种,Android,Java8,IOS。至此,我们知道了 Retrofit 有一个 Platform 对象叫 Android。

继续看到 build 方法。

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 是一定要设置的。不然抛出异常就 GG 了。因为是第一次调用 build 方法来创建 Retrofit,很多参数都是还没有配置的。

比如:

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

刚才已经知道了 Retrofit 有一个 Platform 对象叫 Android。所以这时我们跟进到 Android 的defaultCallbackExecutor方法。如下:

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

返回了一个 MainThreadExecutor,好了,从这里我们可以得出结论,那个 callbackExecutor 就是 MainThreadExecutor,当 callbackExecutor 调用 execute 方法时,就切换到了主线程。

继续前进,来到

adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

这是一行很神奇的代码,首先,还是调用 Platform 的方法,将刚才得到的 callbackExecutor,也就是 MainThreadExecutor,又传进了自己的defaultCallAdapterFactory 方法,这个 defaultCallAdapterFactory 内部生成了一个 ExecutorCallAdapterFactory。

好了,上面那一行神奇的代码,其实就是将一个 ExecutorCallAdapterFactory 添加进一个集合。
我们在创建 Retrofit 的时候,调用了 addCallAdapterFactory 配置了RxJavaCallAdapterFactory。这个 CallAdapter.Factory 也添加进了刚才的集合

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

ExecutorCallAdapterFactory 和 RxJavaCallAdapterFactory 都是继承自
CallAdapter.Factory 的。我们猜,这两个 CallAdapter.Factory 是干什么用的?是用来将结果适配的。

接着继续,同理,

List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);

这是将配置的 GsonConverterFactory 添加进来一个集合。

到这里,创建Retrofit对象完毕。总结一下,其实就是配置参数嘛。

创建接口对象

创建了 Retrofit 对象,调用 create 方法来创建接口对象,比如:

IUserBiz userBiz = retrofit.create(IUserBiz.class);

使用了动态代理来创建接口对象,跟进 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);        }      });}

通过 create 方法拿到了接口对象后,接口对象肯定需要调用接口方法吧,

调用接口方法

Call<List<User>> call = userBiz.getUsers();

当调用接口方法的时候,就会调用到 InvocationHandler 的 invoke 方法,执行其内部的逻辑。

我们看到,调用了接口方法返回的了一个 Call 对象,如果设置了RxJavaCallAdapterFactory,返回的就是一个 Observable 对象。

那么结论我们已经知道了,invoke 方法内部的逻辑就变的很神秘,他到底是怎么返回一个 Call 对象或 Observable 对象的呢?

看到 loadServiceMethod 方法,这里传进了一个 Method 对象,即我们调用的接口方法。(方法也是对象,是 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;}

从 Cache 这个字眼可以猜测是先从缓存中查找,一个 method 对象对应一个 ServiceMethod 对象。
如果缓存不存在,使用建造者模式来创建 ServiceMethod 对象,之后在添加进缓存。好,看下怎么创建 ServiceMethod 对象。同样先是看 Builder 的构造方法,

public Builder(Retrofit retrofit, Method method) {  this.retrofit = retrofit;  this.method = method;  this.methodAnnotations = method.getAnnotations();  this.parameterTypes = method.getGenericParameterTypes();  this.parameterAnnotationsArray = method.getParameterAnnotations();}

这里做了一些初始化工作,取出了接口方法的注解、参数类型、参数的注解。

好的,回到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);}

首先 createCallAdapter() 获取的是创建 Retrofit 时设置的 CallAdapterFactory,一开始我们设置了 RxJavaCallAdapterFactory。同理 createResponseConverter() 方法获取的是 GsonConverterFactory。

接着,就是从接口方法注解数组中取出注解,并调用 parseMethodAnnotation 解析。如果没有设置请求方法的注解等,比如@GET、@POST,会抛出异常的。最后是解析方法参数的注解。创建了 ServiceMethod。

ServiceMethod(Builder<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。

有了 ServiceMethod 后,回到 invoke 方法,会创建 OkHttpCall,

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

只是进行了一些赋值。

最后,关键来了

return serviceMethod.callAdapter.adapt(okHttpCall);

刚才我们提到,在 serviceMethod 的创建过程,会拿到创建 Retrofit 时设置的 callAdapter,所以这里的 serviceMethod.callAdapter,就是RxJavaCallAdapterFactory,那么直接看到 RxJavaCallAdapterFactory 的 adapt 方法即可。

@Override public <R> Observable<Response<R>> adapt(Call<R> call) {  Observable<Response<R>> observable = Observable.create(new CallOnSubscribe<>(call));  if (scheduler != null) {    return observable.subscribeOn(scheduler);  }  return observable;}

返回了一个 observable,之后就可以把复杂逻辑都能穿成一条线了。

如果,我并不想使用 RxJava,即没有设置 RxJavaCallAdapterFactory 呢?
这时 serviceMethod.callAdapter 又是什么?当然是 ExecutorCallAdapterFactory。如下:

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

创建了 ExecutorCallbackCall,并将 MainThreadExecutor 和 OkHttpCall 传进。ExecutorCallbackCall 当然是继承自Call的。也就是返回给我们的Call对象。

那么现在看到 ExecutorCallbackCall 就好了。注意,这里传进的 call 是 OkHttpCall。好,继续前进。看到构造方法

ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {  this.callbackExecutor = callbackExecutor;  this.delegate = delegate;}

喔,OkHttpCall 变成了 delegate。到这里就好了。

执行Call

之后,如果我们拿到的是Call对象,使用姿势是这样的:
异步:

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

同步:

call.execute();

ok,那我们现在回来看,这个 call 调用 enqueue或execute,实际上调用的是ExecutorCallbackCall 的 enqueue 或 execute 方法。我们分析 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);        }      });    }  });}

可以看到,把请求的任务转交给了 delegate,也就是 OkHttpCall。
而 callbackExecutor,也就是 MainThreadExecutor,调用了 execute 方法,在这里完成了线程的切换,具体如下:

static class MainThreadExecutor implements Executor {  private final Handler handler = new Handler(Looper.getMainLooper());  @Override public void execute(Runnable r) {    handler.post(r);  }}

ok,那么现在只需要关注到 OkHttpCall 即可。同样看到入队方法,如下:

@Override public void enqueue(final Callback<T> callback) {  if (callback == null) throw new NullPointerException("callback == null");  okhttp3.Call call;  Throwable failure;  synchronized (this) {    if (executed) throw new IllegalStateException("Already executed.");    executed = true;    call = rawCall;    failure = creationFailure;    if (call == null && failure == null) {      try {        call = rawCall = createRawCall();      } catch (Throwable 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)        throws IOException {      Response<T> response;      try {        response = parseResponse(rawResponse);      } catch (Throwable e) {        callFailure(e);        return;      }      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();      }    }  });}

可以看到,OkHttpCall只是包装了Okhttp,咦,其实这个从名字也能猜出来的。底层实现还是Okhttp。createRawCall 方法会调用 serviceMethod.toRequest 生成一个 Request ,这时那些通过解析注解获取的httpMethod终于派上用场了,toRequest 大概是这样的,可以脑补一下:

    RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,        contentType, hasBody, isFormEncoded, isMultipart);

你可能会疑惑,GsonConverterFactory 为什么没有用到?其实是有的,需要继续跟进一下,当 Okhttp 请求成功,会调用 parseResponse 方法来解析结果,看到这个方法没?看到了
在 parseResponse 方法中, serviceMethod 会调用 toResponse 方法,对结果进行转换,使用的是 Gson。

好了,相信同步调用也可以分析了。当然,如果是使用 observable,和 call 对象调用是同理的。

全文完毕!

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 网销客户不说话怎么办 两岁宝宝不说话怎么办? 4岁儿童说话结巴怎么办 3岁宝宝说话结巴怎么办 6岁儿童舌头短怎么办 5岁宝宝说话结巴怎么办 两岁宝宝说话晚怎么办 6岁儿童说话结巴怎么办 2岁宝宝呕吐拉稀怎么办 2岁宝宝突然呕吐怎么办 2岁宝宝呕吐发烧怎么办 2岁宝宝呕吐厉害怎么办 1岁宝宝半夜呕吐怎么办 2岁半宝宝呕吐怎么办 2岁宝宝半夜呕吐怎么办 两岁宝宝一直吐怎么办 原画师老了以后怎么办 孩子不想上学怎么办怎么去说服 嫉妒别人比我好怎么办 三岁宝宝爱打人怎么办 1岁宝宝喜欢打人怎么办 ps图层解锁不了怎么办 沈腾结婚马丽怎么办 延长甲没有纸托怎么办 高考第一志愿没录取怎么办 电子画颜料干了怎么办 数字画颜料干了怎么办 彩砂纸画不好了怎么办 宝宝吃了油画棒怎么办 2岁宝宝不爱刷牙怎么办 两岁宝宝不刷牙怎么办 1岁宝宝不爱刷牙怎么办 3岁宝宝不肯刷牙怎么办 20岁没学历迷茫怎么办 四岁了不长头发怎么办 17岁掉头发严重怎么办 头发很油,又少怎么办 25岁头发变稀怎么办 宝宝头发少又黄怎么办 头旋附近头发少怎么办 25岁掉头发严重怎么办