根据《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 serviceMethod =
(ServiceMethod) loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod, args);
return serviceMethod.adapt(okHttpCall);
}
});
}
create方法的入参是一个Interface的Class对象,但是返回的是一个Proxy.newProxyInstance代理对象,因为我们在使用Retrofit的时候只需要定义API接口及其对应的方法,而不需要自己implements API interface.但是接口的方法是用来执行的,你不实现接口怎么能执行呢?代理对象的强大之处就体现出来了: 只需要根据你传入的接口,生成一个代理对象,之后所有的方法调用都会走代理对象invoke方法;且代理对象不需要关心你具体执行方法的名字,一律以method表示. InvocationHandler接口只有一个方法,即invoke()方法!它是对代理对象所有方法的唯一实现。也就是说,无论你调用代理对象上的哪个方法,其实都是在调用InvocationHandler的invoke()方法。我们只需要invoke对Method和args进行处理即可。
可以说Retrofit就是利用代理对象的这一特性,将网络框架的使用简易化:
因为API接口所有方法调用的目的就是把方法的注解信息以及参数信息进行扫描和解析,交给OkhttpCall进行处理执行网络调用,既然所有的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
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?