本文基于Retrofit2.5.0进行源码分析,以发送一个异步get网络请求为例,直到取回数据再渲染到页面的整个过程。Gif示例如下:
本文不过多解释Retrofit是怎样使用的,本文假设你已经使用过它并对其有一定程度的了解,那么你应该清楚它有几个可以自由配置的属性分别是:callFactory、converterFactories、callAdapterFactories、callbackExecutor;掌握这几个属性对于理解Retrofit源码起着关键作用。
callFactory:网络请求器,用于发起真正的网络请求。
converterFactories:数据转换器,用于将网络请求的结果转换成你想要的目标数据结构,比如Gson、Jackson、Simple XML。
callAdapterFactories:网络请求适配器,用于将网络请求包装成不同的类型,如默认的Call、RxJava2的Observable、Kotlin的coroutines。
callbackExecutor:回调执行器,用于将网络请求的结果从子线程拉回到主线程。
使用Retrofit发送一个网络请求的代码如下所示,你也可以直接下载demo运行。
//step1:创建Retrofit实例
val retrofit = Retrofit.Builder()
.baseUrl("http://gank.io/api/")
.addConverterFactory(GsonConverterFactory.create())
.build()
//step2:创建接口服务类的代理对象,这里是gankService
val gankService = retrofit.create(GankService::class.java)
//step3:访问接口服务类中的具体业务方法,得到一个适配器对象,这里的categoriesCall是Call<ResponseCategory>类型
val categoriesCall = gankService.categories()
//step4:通过categoriesCall发起网络请求,在Callback中解析数据并处理后续业务逻辑。
categoriesCall.enqueue(object : Callback<ResponseCategory> {
override fun onFailure(call: Call<ResponseCategory>, t: Throwable) {
Log.e("MainActivity", "访问失败", t)
}
override fun onResponse(call: Call<ResponseCategory>, response: Response<ResponseCategory>) {
val body = response.body()
body?.takeIf { result -> !result.isError }?.also { category ->
Toast.makeText(this@MainActivity, "访问成功 -> " + Gson().toJson(category), Toast.LENGTH_SHORT).show()
}
}
})
在上面代码中对step1至step4做了详细的注释,这四个步骤基本就是Retrofit发起网络请求的流程。但源码分析还可以继续深究,在step4发起网络请求时,其中的细节还有很多精彩好戏。这里看上去是categoriesCall这个适配器发起网络请求,但它并不具备这个能力,真正发起网络请求的是callFactory这个网络请求器,callFactory作为网络请求适配器中的一个属性,在构造时就被传到了网络请求适配器中,这里的细节后续会结合代码和debug截图再次分析。
当拿到网络请求返回结果后,会将数据给到数据转换器转换成你想要的目标数据结构,这步我们看作是step5,这个步骤发生在OkHttpCall中。
demo中我们发起异步请求,所以目标数据转换成功后,需要将执行线程从子线程切换到主线程,这步我们看作是step6,这个步骤发生在ExecutorCallbackCall中;另外如果发送同步请求时,是没有这一步骤的。
所以利用Retrofit发送一个异步get网络请求,具体流程如下:
step1. 创建Retrofit实例
step2. 创建网络请求接口服务类的代理对象
step3. 通过代理对象访问接口服务类中的具体业务方法
step4. 通过网络请求结果适配器发起网络请求
step5. 通过数据转换器转成目标数据结构
step6. 通过回调器将代码执行从子线程拉回到主线程
step1. 创建Retrofit实例
下面的代码是最简洁的创建Retrofit实例的代码,这里只配置了数据转换器,其余没有配置的属性,如callFactory、callAdapterFactories、callbackExecutor都采用默认的,接下来会详细分析。
val retrofit = Retrofit.Builder()
.baseUrl("http://gank.io/api/")
.addConverterFactory(GsonConverterFactory.create())
.build()
首先这里通过外观模式,提供了一个统一的接口(Retrofit)用来访问子系统中的一群接口。然后通过建造者模式,配置了baseUrl以及ConverterFactory。建造者模式将Retrofit这个对象的构造过程抽象了出来,开发者可以灵活的组合和配置这几个属性。如若不采用这种方式,Retrofit务必要提供多种重载的构造函数来满足不同开发者的需求,现在通过这种设计模式,直接将这个问题抛给了开发者,开发者要用哪个则配置哪个。
在Retrofit.Buildre()的源码中,有如下构造函数:
public Builder() {
this(Platform.get());
}
这里需要重点分析下Platform这个类,这个类描述了Retrofit当前处于哪个平台,以及callFactory等属性的默认实现。在2.5.0版本的源码中区分三个平台:Android、Java8以及默认的Platform。源码如下所示:
class Platform {
private static final Platform PLATFORM = findPlatform();
static Platform get() {
return PLATFORM;
}
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
if (Build.VERSION.SDK_INT != 0) {
//Android平台
return new Android();
}
} catch (ClassNotFoundException ignored) {
}
try {
Class.forName("java.util.Optional");
//Java8平台
return new Java8();
} catch (ClassNotFoundException ignored) {
}
//默认平台
return new Platform();
}
...
}
我们重点分析Android平台下的表现,源码如下所示,defaultCallbackExecutor()中返回了MainThreadExecutor的实例对象,里面创建了一个基于主线程looper的handler对象;defaultCallAdapterFactories()中创建了ExecutorCallAdapterFactory的实例对象,它是Android平台默认的网络请求结果适配器工厂;defaultConverterFactories()中在SDK24及以上的版本创建了OptionalConverterFactory的实例对象,在24以下是EmptyList的实例。
static class Android extends Platform {
@IgnoreJRERequirement // Guarded by API check.
@Override boolean isDefaultMethod(Method method) {
if (Build.VERSION.SDK_INT < 24) {
return false;
}
return method.isDefault();
}
//默认回调执行器
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
//默认网络请求结果适配器的工厂列表
@Override List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
ExecutorCallAdapterFactory executorFactory = new ExecutorCallAdapterFactory(callbackExecutor);
return Build.VERSION.SDK_INT >= 24
? asList(CompletableFutureCallAdapterFactory.INSTANCE, executorFactory)
: singletonList(executorFactory);
}
@Override int defaultCallAdapterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 2 : 1;
}
//默认数据转换器的工厂列表
@Override List<? extends Converter.Factory> defaultConverterFactories() {
return Build.VERSION.SDK_INT >= 24
? singletonList(OptionalConverterFactory.INSTANCE)
: Collections.<Converter.Factory>emptyList();
}
@Override int defaultConverterFactoriesSize() {
return Build.VERSION.SDK_INT >= 24 ? 1 : 0;
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
这里可以看到网络请求结果适配器和数据转换器都采用了工厂模式,你只要将工厂配置进来,至于怎么创建对象,则不需要你过多关心,只需要知道调用create()就可以。
我们回到代码主线分支,在执行到Retrofit.Buildre().build()时,就会将刚才基于Andorid平台各个属性的默认配置传入到Retrofit的构造函数中,最后通过new关键字创建好Retrofit实例对象,源码如下:
//build源码
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//网络执行器,demo中没有设置,故采用默认的OkHttpClient
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//回调执行器,这里用到了装饰者模式,这里本来想要一个普通的Executor
//然后返回了一个带有线程切换功能的Executor,动态地将责任附加到callbackExecutor上
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//网络请求结果适配器
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
//数据转换器
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
//构造Retrofit实例对象
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
总结:在这一步中,通过建造者模式,灵活配置所需的各个属性(网络请求器、数据转换器、网络请求结果适配器、回调执行器),最后通过new关键字创建Retrofit的实例对象。遇到没有配置的属性,则通过Platform找到对应的平台,然后再找到该平台下的各个属性的默认配置,最后将属性值递到Retrofit的构造函数中。数据转换器和网络请求结果适配器还采取了工厂模式,隐藏具体的创建细节,让具体工厂自己创建其对象。
step2. 创建网络请求接口的代理对象
通过Retrofit实例创建代理对象的源码如下所示,传入参数是网络请求服务接口的Class对象(即GankService),返回的是该接口的代理对象。
val gankService = retrofit.create(GankService::class.java)
在2.5.0版本的Retrofit源码中,create的源码如下所示,因为我们没有设置validateEagerly的值,所以它默认false,然后就是通过Proxy.newProxyInstance创建代理对象。
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();
private final Object[] emptyArgs = new Object[0];
@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.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
newProxyInstance方法中的第一个参数service.getClassLoader()得到类加载器是PathClassLoader,它是Android系统默认的类加载器 (另外DexClassLoader与PathClassLoader的区别感兴趣的童鞋可以自行查阅资料) ;第二个参数是GankService接口的Class对象,这个数组表明要代理哪些接口;第三个参数是动态代理对象,就是外部调用GankService的业务方法时,实际上会被代理回调到这里,然后在invoke方法里面准备网络请求所必须的全部实例对象,如:callAdapter选哪个,responseConverter选哪个等。下面截图是debug create方法的标注说明:
总结:在这一步中,Retrofit通过代理模式创建代理对象,当你在外部调用业务方法时会进行拦截,然后进入到InvocationHandler的invoke方法中控制程序的执行逻辑和流程。
step3. 通过代理对象访问接口服务类中的具体业务方法
前面两步分别创建了Retrofit实例,然后通过该实例创建了网络请求接口的代理对象,接下来就是通过代理对象访问接口服务类中的具体业务方法,对应如下代码:
val categoriesCall = gankService.fetchCategories()
下面截图是debug gankService.fetchCategories方法的标注说明:
通过上面截图可以看到调用gankService.fetchCategories()后,程序流程来到了InvocationHandler的invoke方法中,这里主要分析这句:return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);。这里分三步走,第一步:loadServiceMethod(method);第二步:invoke(args != null ? args : emptyArgs);第三步:return。
loadServiceMethod(method)
loadServiceMethod顾名思义就是将加载fetchCategories()这个method对象,这个方法会返回一个ServiceMethod类型的实例,实际上是返回HttpServiceMethod类型。下面是loadServiceMethod的源码,可以看到进入该方法,会先从serviceMethodCache缓存中去取(这里用到单例模式思想),没有的话就上锁然后解析method的注解。
ServiceMethod<?> loadServiceMethod(Method method) {
//先取缓存
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
//上锁
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//解析method对象的注解
result = ServiceMethod.parseAnnotations(this, method);
//存入缓存
serviceMethodCache.put(method, result);
}
}
return result;
}
下面我们重点分析ServiceMethod是怎样解析method对象的注解的。进入到ServiceMethod.parseAnnotations,源码如下:
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//RequestFactory描述了一个网络请求所需的全部属性
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//将retrofit实例、method实例以及requestFactory实例传到HttpServiceMethod中去解析
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
可以看到第一行通过RequestFactory去解析注解,得到一个RequestFactory实例对象,这个对象非常重要,它包含了网络请求的所有必要数据,我们可以将其看作是一个网络请求的对象描述。RequestFactory解析源码如下,这里并不是完整源码,只截取关键部分用于说明流程,下面的代码都在必要处添加了注释。
//RequestFactory中的所有属性
private final Method method;
private final HttpUrl baseUrl;
final String httpMethod;
private final @Nullable String relativeUrl;
private final @Nullable Headers headers;
private final @Nullable MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
//用建造者模式按需拼装各个属性
return new Builder(retrofit, method).build();
}
//Builder类的构造函数,保存method和methodAnnotations以及参数信息
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations();
this.parameterTypes = method.getGenericParameterTypes();
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
//build方法关键代码
RequestFactory build() {
//循环解析methodAnnotations
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
}
//解析方法体注解的关键源码
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);
} 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) {
...
} else if (annotation instanceof Multipart) {
...
} else if (annotation instanceof FormUrlEncoded) {
...
}
}
//解析参数的关键代码,里面再通过parseParameter解析每个注解
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
parameterHandlers[p] = parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p]);
}
//build方法的最后一句构造了一个描述网络请求的工厂
return new RequestFactory(this);
下面截图是debug RequestFactory.parseAnnotations方法的标注说明:
小结下这一步,RequestFactory通过其自身的静态方法parseAnnotations解析出method对象上的所有注解,最终通过 new RequestFactory(this); 构造出一个描述网络请求的工厂并将其返回。至此我们拿到了描述一个网络请求的工厂,接着ServiceMethod的parseAnnotations往下看,程序会执行 HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory); 这一句,其源码如下所示:
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
//网络请求适配器
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method);
Type responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
//数据转换器
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
//okhttp3.Call.Factory,这里就是OkHttpClient
okhttp3.Call.Factory callFactory = retrofit.callFactory;
return new HttpServiceMethod<>(requestFactory, callFactory, callAdapter, responseConverter);
}
首先会创建网络请求适配器,接着创建数据转换器,再获取之前配好的okhttp3.Call.Factory以及上文创建的requestFactory,最后一并传入到HttpServiceMethod的构造函数中。经过这么多的步骤,我们发现到这里其实全在准备Retrofit所需的各个零部件,不过也算是全部准备就绪。此时我们会得到一个HttpServiceMethod,该对象包含了发送网络请求的所有必要零部件,下面截图是debug HttpServiceMethod.parseAnnotations方法的标注说明:
这里以创建网络请求适配器为例说明Retrofit中是怎样选择合适的适配器的,另外选择数据转换器的逻辑差不多,故不再细述。createCallAdapter源码如下所示:
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(Retrofit retrofit, Method method) {
//得到返回值类型
Type returnType = method.getGenericReturnType();
//得到所有注解
Annotation[] annotations = method.getAnnotations();
try {
//noinspection unchecked
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
先通过method对象拿到返回值类型和注解数组,再通过retrofit实例对象的callAdapter,传入返回值类型和注解,来寻找合适的CallAdapter,这里其实用到了策略模式,根据不同的返回值类型拿到不同的callAdapter就是一种策略选择,retrofit.callAdapter的源码如下所示:
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,Annotation[] annotations) {
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
...
}
可以看到其实就是在callAdapterFactories这个集合对象中寻找一个跟返回值类型匹配的callAdapter。因为我们处于Android平台上,又是默认的callAdapter,所以callAdapterFactories.get(i)这里得到的实际就是ExecutorCallAdapterFactory,再调用里面的get方法得到一个类型匹配的CallAdapter,这个网络请求结果适配器能发起真正的网络请求。这里得到的是默认的网络请求结果适配器:ExecutorCallbackCall。源码如下所示:
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
//默认的网络请求结果适配器
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
...
}
小结下这里就是创建了HttpServiceMethod实例对象,这个实例对象包含了网络请求适配器,数据转换器,okhttp3.Call.Factory以及网络请求工厂requestFactory。
invoke(args != null ? args : emptyArgs)
为了更好的说明调用流程,下面截图是debug Retrofit的create方法中的invoke方法的标注说明:
这里其实调用了上面HttpServiceMethod实例对象的invoke方法,源码如下所示,首先会创建OkHttpCall的实例对象,OkHttpCall实现了Retrofit的Call接口,Call接口描述的是发起网络请求的功能,包括同步和异步两种方式。所以这里的OkHttpCall并不是真正的okhttp3.Call,只是Retrofit对网络请求功能的一种包装。
//HttpServiceMethod的invoke方法
@Override ReturnT invoke(Object[] args) {
//就是上面的ExecutorCallbackCall
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
//OkHttpCall实现了Call
final class OkHttpCall<T> implements Call<T> {
...
OkHttpCall(RequestFactory requestFactory, Object[] args,
okhttp3.Call.Factory callFactory, Converter<ResponseBody, T> responseConverter) {
this.requestFactory = requestFactory;
this.args = args;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}
...
}
//Retrofit中的Call接口,描述了网络请求的功能
public interface Call<T> extends Cloneable {
...
//同步执行
Response<T> execute() throws IOException;
//异步执行
void enqueue(Callback<T> callback);
//网络请求
Request request();
...
}
总结:在这一步中,外部通过代理对象访问接口服务类中的具体业务方法,即:gankService.fetchCategories()。此时会被代理对象的InvocationHandler拦截执行它里面的invoke方法,该方法会得到一个HttpServiceMethod实例对象,并调用它自身的invoke方法;进入HttpServiceMethod中的invoke方法后,接下来的流程便会转入到callAdapter,实际会转入到ExecutorCallAdapterFactory的adapt中,最终会返回一个带有回调功能的适配器。这个跟我们在GankService中定义的业务方法fetchCategories返回值类型一致:Call<ResponseCategory>,不过Call的实际类型是ExecutorCallbackCall而已。
step4. 通过适配器发起网络请求
终于拿到了网络请求结果适配器,此时可以发起同步或者异步的网络请求了,demo中发起了异步请求,所以这里分析异步流程,同步请求流程可自行debug调试。
categoriesCall.enqueue(object : Callback<ResponseCategory> {
override fun onFailure(call: Call<ResponseCategory>, t: Throwable) {
Log.e("MainActivity", "访问失败", t)
}
override fun onResponse(call: Call<ResponseCategory>, response: Response<ResponseCategory>) {
val body = response.body()
body?.takeIf { result -> !result.isError }?.also { category ->
Toast.makeText(this@MainActivity, "访问成功 -> " + Gson().toJson(category), Toast.LENGTH_SHORT).show()
}
}
})
上文中提到过categoriesCall的实际类型是ExecutorCallbackCall,下面是ExecutorCallbackCall的部分源码,在enqueue()中执行delegate.enqueue,这里的delegate的实际类型是OkHttpCall,所以实际上执行了OkHttpCall里面的enqueue方法。
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;//回调执行器
final Call<T> delegate;//实际类型是OkHttpCall
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的enqueue()
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 {
//成功时的回调,此时response就是目标数据结构,将这份数据传回到业务调用发起的地方
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);
}
});
}
});
}
...
}
下面debug截图也验证了delegate的类型:
下面是OkHttpCall中的enqueue方法源码,终于要发起网络请求了,在这个方法里面定义了okhttp3.Call类型的call,然后通过createRawCall方法创建了真正的网络请求执行器,后面再通过call.enqueue发起了真正的网络请求。一路分析下来,终于发起了真正的网络请求,开不开心,激不激动...
@Override public void enqueue(final Callback<T> callback) {
//主要类型是okhttp3.Call
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//创建okhttp3.Call类型的原始Call对象,这个对象才真正具备发送网络请求的能力
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
//通过call对象发起异步网络请求
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response;
try {
//解析网络请求的结果数据
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e);
return;
}
try {
//通过callback回调到ExecutorCallbackCall中
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
这一步的流程基本分析结束,接下来分析okhttp3.Call的实例对象是如何创建的,我们看下createRawCall方法的源码:
private okhttp3.Call createRawCall() throws IOException {
//通过callFactory的newCall(),传入requestFactory所描述的一个网络请求所需的必要属性,创建了okhttp3.Call的实例对象。
//这里callFactory的实际类型是OkHttpClient。
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
requestFactory.create(args)这里会创建一个okhttp3.Request,requestFactory描述了一个网络请求所需的完整信息。而callFactory实际上是okhttp3.Call.Factory类型,在创建Retrofit实例的时候就配置好了,实际上就是OkHttpClient的实例对象。这里通过OkHttpClient和okhttp3.Request创建了一个okhttp3.Call。下面截图展示了okhttp3.Call的组成部分:
总结:在这一步中,外部通过网络请求结果适配器发起异步的网络请求 (categoriesCall.enqueue()),实际执行流程是:ExecutorCallbackCall的enqueue -> OkHttpCall的enqueue -> okhttp3.Call的call调用enqueue。
step5. 通过数据转换器转成目标数据结构
在上面的代码片段中,在call.enqueue里面拿到请求结果后,会调用 parseResponse(rawResponse); 解析rawResponse为目标数据结构,源码如下:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
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);
}
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//真正转换数据的地方
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
catchingBody.throwIfCaught();
throw e;
}
}
关键一句是 T body = responseConverter.convert(catchingBody); 将rawBody转成了目标T,responseConverter是创建OkHttpCall时就传入进来的。下面debug截图展示了response中存放的目标数据结构就是我定义的ResponseCategory类型。
step6. 通过回调器将代码执行从子线程拉回到主线程
在得到目标数据结构之后,在OkHttpCall的enqueue中会通过如下回调函数将结果传到ExcutorCallback中。
try {
//这里的callback实例是在ExecutorCallbackCall中通过new Callback()传进去的,所以回调时回到ExcutorCallback中
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
在ExcutorCallback类中,会通过callbackExecutor对象将结果回调到主线程中,这里的callbackExecutor实际上就是step1中提到的MainThreadExecutor的实例对象,这样就回到了主线程中,然后再执行接下来的业务方法,demo中就是将结果展示了一下。源码如下所示:
//实际执行的是OkHttpCall的enqueue()
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 {
//成功时的回调,此时response就是目标数据结构,将这份数据传回到业务调用发起的地方
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);
}
});
}
});
下面debug截图是callback调用onResponse方法回到业务代码中的标示说明:
总结:在这一步中,主要是通过MainThreadExecutor将结果从子线程拉回到主线程,再接着执行后面的业务逻辑。
一点感想
为了便于自己有个完整的影响,画了一张Retrofit发送一个网络请求流程中所涉及的类的说明图:
Retrofit本质上是遵循了RESTful风格、通过大量的设计模式封装OkHttp的HTTP网络请求框架,使用起来简洁而优雅。Retrofit将Http请求抽象成Java接口,在接口里用注解描述和配置网络请求参数,用动态代理的方式进行拦截,动态将网络请求接口的注解解析成HTTP请求,最后执行HTTP请求。
Retrofit框架通过大量的设计模式使得代码高度内聚,少量耦合,灵活又轻巧,或许这是每位coder都该追求的一种境界。Retrofit中用到的设计模式有:外观模式、代理模式、策略模式、单例模式思想、建造者模式、工厂方法模式、装饰模式。所以想学习设计模式的你一定不能错过它。