前言:站在巨人的肩膀上聊聊我对Retorfit这个联网框架的了解。诸多好处我就不详细说明了,两句话来总结一下,Retorfit是一个面向接口的注解型联网框架,底层实现原理就是Java的动态代理。
1.基本使用和建议
- 现在网上对于Retorfit的使用姿势已经足够多了,不过我还是建议去Retorfit官方学习。
- 虽然Reorfit已经足够简单了,但是往往并不能满足我们的需求,建议在这基础之上,根据自身业务的区别进行二次封装。http网络模块简易封装
2.进入正题,源码分析
2.1学习目标
- 了解Retorfit对象创建需要什么元素,分别又是做什么用的。
- Retorfit中的create方法到底做了什么
- Retrofit的ConverterFactory; CallAdapterFactory方法设置的Converter.Factory和CallAdapter.Factory对象何时何地起作用
- Call对象及其execute和queue方法的内部逻辑
2.2Retorfit.class
2.2.1 Retorfit.class中的Fileds说明
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
unmodifiableList方法和unmodifiableList类似,通过方法上方官方给的注释得知此方法提供一个一个只读的访问权限,意思是不可通过该对象对list集合中的元素进行任何修改,简单的意思就是保证数据的list的集合只可以在创建新对象时可以修改。
Retorfit$Build.class中的Fileds基本就和Retorfit.class差不多,多了一个Platform属性,
Platform属性在Android会默认获取到一个这样的对象
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);
}
}
}
简单的概述一下就是给Retorfit添加一系列默认属性的地方。
2.2.2走进create方法
public <T> T create(final Class<T> service) {
/**
* 检查参数Service是不是一个接口,接口中是否有定义方法;否则抛出异常
*/
Utils.validateServiceInterface(service);
if (validateEagerly) {
/**
* 开启了预校验则提前校验接口内部所有方法,通过对每个方法的注解解析并得到一个ServiceMethod对象,并缓存在
* serviceMethodCache中。默认是延迟加载,也就是不会提前校验。
*/
eagerlyValidateMethods(service);
}
/**
* 创建了一个动态代理,上层调用接口中的方法,实际上都会运行代理类的方式执行,也是Retorfit的精髓所在
*/
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.
/**
* 反射出来的代理对象也是Object对象,如果是调用来自Object对象的方法,则走本身的方法,例如equals等方法
*/
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
/**
* java8的兼容,Android这里永远为false,不会走进此反射方法内。
*/
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
/**
* 从缓存中获取ServiceMethod对象,如果没有就创建一个临时的,并添加进缓存。
*/
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
/**
* 创建一个OkHttpCall对象,该对象相对于okhttp3.Call会在网络请求前后对数据
* 利用该方法对应的数据转换器进行一定的转换,之后内部再通过okhttp3.Call发送请求
*/
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
/**
* 通过返回值,来找到可以解析的网络请求适配器工厂,并执行返回结果。默认是call
*/
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
2.2.3走进loadServiceMethod方法
ServiceMethod<?, ?> loadServiceMethod(Method method) {
/**
* 从缓存中获取ServiceMethod对象,如果有值直接返回
*/
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
/**
* 如果为null,则使用当前retorfit和m需要运行的method方法创建一个ServiceMethod对象
* 并且添加到ConcurrentHashMap中,保证线程安全
*/
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
小结一下,此处的大致流程,效验是否为接口,是否需要预先效验所有方法是否符合retorfit风格,接下来主要就是创建ServiceMethod对象,然后执行网络请求,得到接口回调,最后OkHttpCall对象传给ServiceMethod中对应的网络请求适配器工厂的adapt方法中,返回的对象类型就是ServiceMethod对应的方法的返回值类型,如Call;
- 2.3 ServiceMethod.class
简单的说明下属性,大部分是构建一个request所需要的参数,这个类的作用就是为了将我们写好的接口转化成一个正常的网络请求,我们来看下比较关键的几个方法。同样都是build构建
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
/**
* 获取方法上的注解
*/
this.methodAnnotations = method.getAnnotations();
/**
* 获取方法的参数类型
*/
this.parameterTypes = method.getGenericParameterTypes();
/**
* 获取方法参数类型上的注解
*/
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
public ServiceMethod build() {
/**
* 找到第一个满足要求的网络请求适配器
*/
callAdapter = createCallAdapter();
/**
* 获取返回值类型
*/
responseType = callAdapter.responseType();
/**
* 返回数据类型不可以为retrofit2.Response.class和okhttp3.Response.class类型,
* Response和Response是有区别的。
*/
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);
}
....
//这里省略一部分判断
....
/**
* 返回ServiceMethod对象
*/
return new ServiceMethod<>(this);
}
createCallAdapter和createResponseConverter方法大致是一样的,这里就简单介绍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);
}
}
第一步获取到返回值类型,拿到方法的注解,最后回调到Retorfit的callAdapter方法中,接着又继续回调到nextCallAdapter方法中
....
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;
}
}
....
从retorfit中找到第一个符合要求的网络请求适配器就直接返回了。同理内容转换器。也是如此,因此我们有时候需要添加返回值为String的时候,我们需要把这个转换器加在最后。
- 2.4 OkHttpCall.class
/**
* 保存了创建request需要的各种参数和retorfit的转换器
*/
private final ServiceMethod<T, ?> serviceMethod;
/**
* 传过来的参数数组
*/
private final @Nullable Object[] args;
/**
* 是否取消请求标记
*/
private volatile boolean canceled;
/**
* 实际上进行联网请求的类
*/
@GuardedBy("this")
private @Nullable okhttp3.Call rawCall;
调用ServiceMethod的toRequest创建一个request请求。
/** Builds an HTTP request from method arguments. */
Request toRequest(@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 requestBuilder.build();
}
调用ServiceMethod中保存的网络请求工厂执行request请求。
private okhttp3.Call createRawCall() throws IOException {
/**
* 调用ServiceMethod的toRequest创建一个request请求。
*/
Request request = serviceMethod.toRequest(args);
/**
* 调用ServiceMethod中保存的网络请求工厂执行request请求。
*/
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
然后拿到数据的返回结果,调用ServiceMethod中保存的数据转换工厂将ResponseBody转化为对象返回。
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
....
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
.....
}
ServiceMethod的toResponse方法
/** Builds a method return value from an HTTP response body. */
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
3.源码总结
- 调用Retrofit的create方法,根据create方法参数(接口类对象)构造一个代理,代理的执行实体是一个InnovationHandler对象。
- 将Method对象转为一个ServiceMethod对象,构造过程会根据方法的标注从Retrofit的ArrayListconverterFactories和ArrayListadapterFactories集合中获取该方法对应的Converter responseConverters和CallAdaptercallAdapter,同时根据方法参数的标注为每个参数创建一个ParameterHandler对象,该对象包含有一个ConverterrequestConverter对象或者一个ConverterstringConverter对象;用于对每个参数进行转换处理。
- 利用前面的ServiceMethod对象和args创建一个OkHttpCall对象,该对象内部会包含一个okhttp3.Call对象,OkHttpCall会在okhttp3.Call对象进行网络访问前后分别利用对应的requestConverter和responseConverter对数据进行相应的转换。
- 通过ServiceMethod的callAdapter对象的adapter方法(参数OkHttpCall)创建一个本Method预期的返回值对象;
- 如果在构造Retrofit的时候没有设置CallAdapter.Factory则都是返回的Call对象,该对象的execute方法和enqueue方法实际上都是直接调用OkHttpCall的同名方法,返回一个Response对象
- 如果在构造Retrofit的时候设置了RxJavaCallAdapterFactory 那么可能返回对象可以定义为Observable类型。
4.资源
* 我的个人博客
* retrofit的Github地址
* Retorfit官方文档