根据《Retrofit源码解析之请求流程概述》我们知道Retrofit通过OkhttpCall来完成同步或者异步请求,那么OkhttpCall的execute和enqueue方法是什么时候开始执行的呢?这篇博文就来简单的扒一扒其内部原理。
简单以Retrofit同步请求作为说明,简单的例子如下:
interface MyApi {
@Get
Call getData(params)
}
MyApi mApi = retrofit.create(MyApi.class);
Call testCall= mApi.getData(params);
//*发送网络请求(同步)
Response response = testCall.execute();
//获取数据
YourBean bean = response.body();
用法很简单,就是先调用Retrofit的create方法获取一个MyApi对象,然后执行某一个getData方法返回一个Call对象,那么这个Call对象会是OkhttpCall吗?答案是No! 下面就抽丝剥茧来分析下这个Call对象是神马牛鬼蛇神。
先来看看Retrofit的create方法:
public T create(final Class 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, @Nullable Object[] args)
throws Throwable {
//省略无关代码
ServiceMethod
create方法的入参是一个Interface的Class对象,但是返回的是一个Proxy.newProxyInstance代理对象,因为我们在使用Retrofit的时候只需要定义API接口及其对应的方法,而不需要自己implements API interface.但是接口的方法是用来执行的,你不实现接口怎么能执行呢?代理对象的强大之处就体现出来了:
只需要根据你传入的接口,生成一个代理对象,之后所有的方法调用都会走代理对象invoke方法;且代理对象不需要关心你具体执行方法的名字,一律以method表示. InvocationHandler接口只有一个方法,即invoke()方法!它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。我们只需要invoke对Method和args进行处理即可。
可以说Retrofit就是利用代理对象的这一特性,将网络框架的使用简易化:
,既然所有的API接口方法调用都是基于同一目的,那么全部就交给代理对象代劳就是了,代理的强大之处被利用的淋漓尽致。
啰嗦了这么多,下面就来看看其invoke方法都做了啥:
//根据你调用的某个method,调用loadServiceMethod方法。获取对应的ServiceMthod对象
ServiceMethod serviceMethod =
(ServiceMethod) loadServiceMethod(method);
//将参数和Service构成一个OkhttpCall对象
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
//数据返回
return serviceMethod.adapt(okHttpCall);
步骤很简单明了:
1、根据你调用某个方法method对象从缓存中获取对应的ServiceMethod对象,如果缓存没有则创建一个。
2、将method对应的serviceMethod及其参数args,初始化一个OkHttpCall对象
3、执行serviceMethod的adapt方法,返回一个Call
ServiceMthod的创建
先看看serviceMethod是怎么创建的:
ServiceMethod, ?> loadServiceMethod(Method method) {
ServiceMethod, ?> result = serviceMethodCache.get(method);
//缓存中有则使用缓存里面的
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//没有缓存则创建一个ServiceMethod
//this是Retrofit
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
看看ServieMethod.Builder方法都有啥:
Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//获取Api某个方法的注解信息
this.methodAnnotations = method.getAnnotations();
//*这个解释有点绕,看https://blog.csdn.net/jiang_bing/article/details/7794365
this.parameterTypes = method.getGenericParameterTypes();
//获取参数的注解信息
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
从上面代码可以看出,Builder的构造器的作用就是拿到一个Method对应的信息,比如方法注解信息,参数注解信息等,然后再来看看Buider的build方法:
CallAdapter callAdapter;
public ServiceMethod build() {
//创建一个callAdapter
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?");
}
//根据returnType创建数据转换器
responseConverter = createResponseConverter();
//解析方法注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//省略部分注解处理代码:详细解析会另外开启博文说明
return new ServiceMethod<>(this);
}
CallAdapter方法简单说明
build方法的第一个步骤就是createCallAdapter()创建一个callAdapter,还记得上面代理对象的invoke方法最后一行吗?即return serviceMthod.adapt(OkhttpCall),内部就是调用了callAdapter的adapt方法:
T adapt(Call call) {
return callAdapter.adapt(call);
}
所以继续瞅瞅createCallAdapter都干了啥:
private CallAdapter createCallAdapter() {
//得到目标方法返回类型对应的Type对象
Type returnType = method.getGenericReturnType();
//获取方法的注解信息
Annotation[] annotations = method.getAnnotations();
//根据热天run
return (CallAdapter) retrofit.callAdapter(returnType, annotations);
}
}
至于返回哪一个CallAdapter,为了博文的条理性,在这里先直接说结论:
返回是CallAdapte是由从Anrdoid Platfom的ExecutorCallAdapterFactory工厂对象生成的
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
//此处的callbackExecutor就是MainThreadExecutor
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
//使用handle来post一个任务
handler.post(r);
}
}
}
ExecutorCallAdapterFactory工厂对象持有一个MainThreadExecutor ,该MainThreadExecutor的作用是将一个任务Runnable都通过handle发送到Android消息队列中去执行。
进而看看这个工厂对象返回的CallAdapter是神马:
@Override
public CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//method方法返回值类型必须是Call
if (getRawType(returnType) != Call.class) {
return null;
}
//获取Call的泛型T的类型
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter>() {
@Override public Type responseType() {
//Call那么返回的就是JavaBean
return responseType;
}
//最终invoke会执行的方法
//adapt方法参数的call就是OKhttpCall
@Override public Call adapt(Call call) {
//callbackExecutor是MainThreadExecutor
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
上述get方法有几个要注意的地方:
1、Api Service定义的方法的返回值必须是Call《T》类型(当然这是没有结合rx使用的情况)
2、CallAdapter的responseType()方法返回的就是对应的JavaBean的类型,正如注释所说:For example, the response type for {@code Call
3、最终CallAdapter的adapt返回的就是ExecutorCallbackCall,而adapt的方法参数就是我们的OKhttpCall(参见文章开头对invoke方法的说明)。也即是说下面的代码中的Call就是ExecutorCallbackCall:
/*实际上返回的就是ExecutorCallbackCall*/
Call call= Api.getData();
Resonse response = call.execute();
T data = response.body();
4、ExecutorCallbackCall持有的callbackExecutor引用指向的对象就是MainThreadExecutor
final class ExecutorCallbackCall<T> implements Call<T>{
//MainThreadExecutor
final Executor callbackExecutor;
//OKhttpCall
final Call delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
}
所以文章开头testCall.execute()执行的就是ExecutorCallbackCall的execute方法,而该方法又是代理给OkhttpCall的execute方法:
//同步网络请求
public Response execute() throws IOException {
//OkhttpCall真正执行的地方
return delegate.execute();
}
那么在看看其异步网络请求:
public void enqueue(final Callback callback) {
//同样执行的是OKhttpCall的enqueue方法
delegate.enqueue(new Callback() {
@Override public void onResponse(Call call, final Response 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 call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
异步请求其实也很简单,其内部就是调用了OkhttpCall的enqueue,只不过在回调结果的时候通过MainThreadExecutor转到了UI线程中去处理了。
到此为止OkttpCall的执行讲解完毕,代码其实很绕,分析其源码的时候各种方法来回跳转,很容易混乱。比如这个OkhttpCall可以直接返回,但是层层代码各种传递才能分析出invoke返回的Call是个什么玩意。为什么本来简单的调用要搞这么复杂呢?这个问题会从代码设计的绝对另开博客详细说明。
总结下来就是:
某ApiService定义的一系烈方法中,你调用了几个个方法,就会对应创建几个ServiceMethod对象,同时也会对应创建几个OkhttpCall来执行。