一、前言:
Retrofit:
一个 Restful 设计风格的 HTTP 网络请求框架的封装。基于 OkHttp
严格地说,Retrofit2并不是一个网络请求交易框架,它只是对网络请求框架的封装。底层把实现交给了okhttp3,由okhttp3做真正的网络请求。Retrofit2框架和其他的用于网络请求的框架流程大体相同,Retrofit2优势在于,它使用了大量的设计模式将功能模块解耦,这样做的好处在于可以让流程更加清晰,可塑性更强。
Retrofit2源码地址:https://github.com/square/retrofit
二、Retrofit 用法
1. 定义请求接
public interface ApiService{
@GET(value = "users")
Call<User>getUser(@Query("id") int userId);
...
}
2. 构建retrofit实例
下面是最简单的构建方式,通过链式调用我们可以为retrofit实例设置很多属性,例如callAdapter,Conventor,OkhttpClient等。
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
3. 创建接口的动态代理对象,以调用接口里的方法。
ApiService service=retrofit.create(ApiService.class);
4. 发起网络请求 ,处理回调结果
new ApiHandler().getService().getUser(1)
.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
}
@Override
public void onFailure(Call<User> call, Throwable t) {
}
});
```
值得注意的是,要想上面的代码获得我们自己设定类型User,需要我们设置自己的Converter,默认的只支持返回responseBody 与Void类型。使用.addConverterFactory(GsonConverterFactory.create())添加了一个Gson的转换器。
retrofit完整的使用也就分为上面4步,那如果你已经用的很溜了,曾几何时是否想过这一切都是怎么做到的呢?这就是下面要解决的问题。
## 三、源码详细分析
本文使用的是retrofit 2.4.0 版本,在读源码的时候发现了一个问题,就是从GitHub拷贝的源码,与直接通过gradle引入Android项目然后在AndroidStudio的类库查看的代码有出入,Retrofit 类如下图所示:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190831162614404.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTA2OTAzNA==,size_16,color_FFFFFF,t_70)
架构流程图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190831162647712.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zOTA2OTAzNA==,size_16,color_FFFFFF,t_70)
#### 1. 关键接口
Retrofit 中有如下4个关键接口:
- Call : 可以理解为一个完整的Http请求活动,向服务器发起请求(Request)得到返回结果(Response)。
- CallAdapter: 将类型参数为R的Call (Call<R>)适配为类型T.例如我可以将OkHttpCall<R>转换成一个Observable<String>输出,Rxjava2Calladapter就是这么干的。
- Converter:这个一说就明白,将一种类型的数据转成另一种类型。例如将ResponseBody转成User类型,这个接口里面的Factory有三个转换器:responseBodyConverter将http请求返回的数据ResponseBody转换为我们需要的类型;requestBodyConverter将我们传入的类型转换为http请求时需要的RequestBody,例如我们使用注解@Body标记了某个类型User,我们就可以使用这个转换器来将User构建为RequestBody的内容。stringConverter将我们传入的类型转换为String
- Callback:http请求回调,一个成功,一个失败,这个没有什么好说的。
#### 2. 关键类:
- Retrofit:配置必要参数,发起构建http Call 的动作。
- ServiceMethod ,HttpServiceMethod :负责组装出一个可以使用的Http 请求的方法,就是根据注解以及我们设置的返回类型,使用我们在retrofit配置的calladapter以及converter 来构建请求方法。HttpServiceMethod 依赖RequestFactory 。
- RequestFactory , RequestBuilder : RequestFactory 的主要目的是构建一个okhttp3.Request ,这就看出了要懂retrofit必须先要对OkHttp有所了解的必要性了。而 RequestBuilder 是协助RequestFactory 来完成这个目标的,它从RequestFactory里面得到一些必要数据后构建出了okhttp3.Request。RequestFactory 依赖RequestBuilder 。
- ParameterHandler:用来处理我们声明的方法里参数上的那些注解的,例如@path,@Url等。其协助RequestFactory 工作,RequestFactory 依赖ParameterHandler。
- OkHttpCall:终于找到了你,这个类才是真正发起http请求的地方,上面的所有类都是为它服务。
#### 3. Retrofit构建
Retrofit类:
```
public Retrofit build() {
...
//设置okhttp callFactory
okhttp3.Call.Factory callFactory = this.callFactory;
...
//可以设置Executor,一般我们都不设置,直接使用系统默认的,对于Android来说就是一个使用Handler切换到主线程的executor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
//设置CallAdapter.Factory列表
//我们可以通过addCallAdapterFactory()方法加入我们自己的adapter,例如rxjava2的callAdapter,
//系统会在其后加入一个默认的Adapter,一旦用户没有指定适配器就使用默认的,Android使用ExecutorCallAdapterFactory
List<CallAdapter.Factory> callAdapterFactories =
new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
//设置Converter.Factory列表
//与上面不同的是,这次首先加入一个默认的,然后才加入用户设定的,上面是先添加用户的,然后添加默认的。
List<Converter.Factory> converterFactories =
new ArrayList<>(1 + this.converterFactories.size());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
//使用设置好的参数来构建Retrofit实例
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
通过build()方法我构建Retrofit实例,接下来就可以调用它的public方法了,其中最为关键的就是create()方法. Retrofit 通过此方法根据我们的接口声明来构建一个Call,然后我们就可以发起网络请求相关操作了。
4. 获得接口代理
Retrofit 类:
public <T> T create(final Class<T> service) {
//省略了检查我们接口文件的合法性以及是否要将所有请求方法缓存起来的代码
...
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();//获得当前平台,此处为Android
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
...
//最关键的就是这句话,获取一个ServiceMethod对象然后构建一个Call对象。
return loadServiceMethod(method).invoke(args);
}
});
}
此方法采用了Jdk动态代理模式,不清楚动态代理的同学请移步到秒懂Java代理与动态代理模式。其实也比较好理解,你定义了一个接口,里面声明了很多方法,那你正常情况下是不是应该有一个这个接口的实现类,然后才能使用里面的方法。所谓动态代理就代理的这个实体类,我们这里的create()返回值就是此动态代理实例,只要使用这个实例调用方法,那么都会进入invoke()方法里面。
Retrofit 类:
//获取一个ServiceMethod,其代表一个完整的http请求方法,先从缓存中拿,如果没有就使用ServiceMethod.parseAnnotations去产生,然后放入缓存中,再返回
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);//关键代码
serviceMethodCache.put(method, result);
}
}
return result;
}
通过这行代码 ServiceMethod.parseAnnotations(this, method);进入ServiceMethod类查看
ServiceMethod类
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//检查我们什么方法返回类型是否合法
...
return new HttpServiceMethod.Builder<Object, T>(retrofit, method).build();
}
abstract T invoke(@Nullable Object[] args);
}
可以看到,真正的逻辑实现是在HttpServiceMethod中,包括构建以及起调。
5. 构建ServiceMethod
HttpServiceMethod类的任务很简单,就是想办法获得下面这几个字段的值
HttpServiceMethod类
private final RequestFactory requestFactory;
private final okhttp3.Call.Factory callFactory;
private final CallAdapter<ResponseT, ReturnT> callAdapter;
private final Converter<ResponseBody, ResponseT> responseConverter;
然后通过invoke()调起方法
//提交一个http请求,返回我们设定的类型的结果,例如Call<User>
@Override ReturnT invoke(@Nullable Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
虽然目的很明确,但是实施过程还是要费一番周折的,下面我们就来抽丝剥茧。
callFactory 的值从传入retrofit实例里面很容易得到的,我们接下来分析剩下的三个
HttpServiceMethod类
callFactory = builder.retrofit.callFactory();//得到了callFactory 的值
HttpServiceMethod<ResponseT, ReturnT> build() {
requestFactory = RequestFactory.parseAnnotations(retrofit, method);//得到了requestFactory 的值
callAdapter = createCallAdapter();//得到了callAdapter 的值
responseType = callAdapter.responseType();//接口声明的返回类型例如Call<User>,那么这个就User
...
responseConverter = createResponseConverter();//得到了responseConverter 的值
...
return new HttpServiceMethod<>(this);
}
6. 构建RequestFactory
获取requestFactory 的值:通过RequestFactory类中的parseAnnotations()方法
RequestFactory类
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
而所谓的构建requestFactory类就是获得该类中如下字段的值
RequestFactory类
private final HttpUrl baseUrl;
final String httpMethod;
private final String relativeUrl;
private final Headers headers;
private final MediaType contentType;
private final boolean hasBody;
private final boolean isFormEncoded;
private final boolean isMultipart;
private final ParameterHandler<?>[] parameterHandlers;
这个类又使用了构建者模式,关键代码都在RequestFactory.Builder中。
RequestFactory类
RequestFactory build() {
//解析方法上的注解,例如@GET,@POST等
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);//关键代码
}
...
//解析参数注解,如@Path,@Query等
//将处理方法参数注解的ParameterHandler放在一个数组中parameterHandlers
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
//参数的类型 @QueryMap Map<String,String>map,那么这个值就是Map<String,String>
Type parameterType = parameterTypes[p];
...
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];//每一个参数上的注解,可能多于一个,所以是数组
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);//关键代码
}
...
return new RequestFactory(this);
}
构建requestFactory需要完成两个主要任务,解析方法上的注解标签,解析方法参数上的注解标签。
RequestFactory类
private void parseMethodAnnotation(Annotation annotation) {
...
if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
isFormEncoded = true;
}
}
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
...
this.httpMethod = httpMethod;
this.hasBody = hasBody;
//没有设置相对路径就解析完毕了
if (value.isEmpty()) {
return;
}
//解析相对路径与查询字符串
int question = value.indexOf('?');
if (question != -1 && question < value.length() - 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
throw methodError(method, "URL query string \"%s\" must not have replace block. "
+ "For dynamic query parameters use @Query.", queryParams);
}
}
this.relativeUrl = value;
this.relativeUrlParamNames = parsePathParameters(value);
}
```
通过上面的代码就将将方法上面的注解标签解析好了,接下来看下参数标签解析,比方法注解复杂一些。下面这个方法是处理方法中某一个参数的逻辑,总体逻辑比较简单:遍历此参数上的所有注解,查看是否存在一个retrofit注解,可以有其他注解,存在则生成一个当前注解的ParameterHandler。
RequestFactory类
```
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
//循环某一个参数上的注解,因为一个参数除了使用Retrofit的注解标注以外,也有可能使用其他注解标注,这里只处理retrofit自己的注解
//如果一个参数上存在两个以上的retrofit注解,则会报错
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);//关键代码
//发现是非Retrofit注解,直接跳过
if (annotationAction == null) {
continue;
}
//发现一个参数上存在两个以上的Retrofit注解,报错
if (result != null) {
throw parameterError(method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
//某个参数不带retrofit注解也是不行的,报错
if (result == null) {
throw parameterError(method, p, "No Retrofit annotation found.");
}
return result;
}
生成ParameterHandler的方法长的令人发指,大概有270多行,但是逻辑比较简单。就是看下当前要处理的注解是retrofit的那个注解,调到相应的逻辑处理单元去处理,所以如果retrofit再增加新的注解,这个方法还要增长,只要增加一个新的注解那么这里就会增加一段处理逻辑。我挑选典型逻辑展示如下
RequestFactory类
private ParameterHandler<?> parseParameterAnnotation(int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
...
gotUrl = true;
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl();//关键代码
} else {
throw parameterError(method, p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
} else if (annotation instanceof Path) {
...
gotPath = true;
Path path = (Path) annotation;
String name = path.value();
validatePathName(p, name);
//注意这里就开始使用converter了,在解析@Path注解的参数时,其类型是要被转换成String的
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(name, converter, path.encoded());
} else if (annotation instanceof Query) {
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);
gotQuery = true;
//针对参数类型为Iterable(例如集合),数组以及其他三种情况作了处理,这段代码基本上把ParameterHandler的功能都涉及到了。
if (Iterable.class.isAssignableFrom(rawParameterType)) {
//必须是泛型
if (!(type instanceof ParameterizedType)) {
throw parameterError(method, p, rawParameterType.getSimpleName()
+ " must include generic type (e.g., "
+ rawParameterType.getSimpleName()
+ "<String>)");
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
...
}
}
至此我们就将方法的注解以及方法参数的注解都处理完了,然后下一步就是使用这些处理后的信息来构建okhttp Request 了,只有有了这哥们我们才能发起Http请求。这个任务是由create()方法完成的
RequestFactory类
//创建了一个okhttp 的 Request,里面使用到了RequestBuilder 类,这个类负责使用RequestFactory类处理出来的信息构建http请求
okhttp3.Request create(@Nullable Object[] args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
//下面的代码比较关键,通过参数信息来完善RequestBuilder ,而这些参数信息存放在parameterHandlers里面,它是通过parseParameter()函数解析出来的
@SuppressWarnings("unchecked") // It is an error to invoke a method with the wrong arg types.
ParameterHandler<Object>[] handlers = (ParameterHandler<Object>[]) parameterHandlers;
...
//关键代码 使用上面得到的ParameterHandler来配置 RequestBuilder
for (int p = 0; p < argumentCount; p++) {
handlers[p].apply(requestBuilder, args[p]);
}
return requestBuilder.build();
}
至此,HttpServiceMethod 中的requestFactory 完成了赋值,是不是已经迷失了,请回到我们最初的道路上来,现在HttpServiceMethod 中还有两字段callAdapter与responseConverter 需要赋值。
7. 获取CallAdapter
HttpServiceMethod类
private CallAdapter<ResponseT, ReturnT> createCallAdapter() {
Type returnType = method.getGenericReturnType();
Annotation[] annotations = method.getAnnotations();
//关键代码
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
}
从上面的方法可以看出,这个callAdapter是通过retrofit的实例方法callAdapter()获得的,转到Retrofit类里面查看
Retrofit类
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
...
//是否要跳过列表中某个callAdapter
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;
}
}
...
}
上面的代码是从我们那个callAdapter列表获得一个callAdapter,如果我们不在构建retrofit的时候设置自定义的callAdapter,那么我们的列表中就只有一个ExecutorCallAdapterFactory,所以我们得到的callAdapter就是它。
8. 获取ResponseConverter
HttpServiceMethod类
private Converter<ResponseBody, ResponseT> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
return retrofit.responseBodyConverter(responseType, annotations);//关键代码
}
从上面的方法可以看出,这个Converter是通过retrofit的实例方法responseBodyConverter()获得的,转到Retrofit类里面查看
Retrofit类
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
...
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
if (converter != null) {
return (Converter<ResponseBody, T>) converter;
}
}
...
}
与获取callAdapter的路子完全一样,现在我们那个converter列表里面也只有一个值BuiltInConverters,所以获取到的就是它。
至此终于构建出了HttpServiceMethod实例,我们可以愉快的调用它的实例函数啦。
9. 调用函数
还记得我们的出发点吗?就是retrofit的create()里的loadServiceMethod(method).invoke(args);,我们前面分析了那么多就解释了loadServiceMethod(method)这半句话,那么下面就是invoke(args)。
HttpServiceMethod类
//提交一个http请求,返回我们设定的类型的结果,例如Call<User>
@Override ReturnT invoke(@Nullable Object[] args) {
return callAdapter.adapt(
new OkHttpCall<>(requestFactory, args, callFactory, responseConverter));
}
那个callAdapter就是通过ExecutorCallAdapterFactory得到的,来看其源码
ExecutorCallAdapterFactory类
final class ExecutorCallAdapterFactory extends CallAdapter.Factory {
final Executor callbackExecutor;
ExecutorCallAdapterFactory(Executor callbackExecutor) {
this.callbackExecutor = callbackExecutor;
}
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
//返回的类型必须是Call 类型
if (getRawType(returnType) != Call.class) {
return null;
}
//例如returnType为:List<User> 那么responseType 就是User
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);
}
};
}
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
@Override public void enqueue(final Callback<T> callback) {
checkNotNull(callback, "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);
}
});
}
});
}
...
}
上面的源代码有三点需要注意
1:看那个get(),就是这里返回了我起调函数的那个callAdapter,所以adapt(),执行的就是
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
可以看到其需要一个Call 类型的参数,我们传入的是OkHttpCall的实例,其实现了Call接口。
2:这里面还有一个CallbackExecutor,这个是在retrofit构建时候传入的,Android平台默认为MainThreadExecutor
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
不知道是不是有亲切的感觉,尼玛总看到了关于Android的东西,Handler!这个CallbackExecutor负责切换线程。所以网络请求后得到的回调就在主线程中了。
3:这里使用了典型的代理模式,不过这次是静态代理。ExecutorCallbackCall 代理了OkHttpCall,他们都实现了接口Call。这样代理就有能力在执行被代理对象的动作是附加一些动作了,例如这里的线程切换。妙哉否?妙哉!
10. 发起请求
至此我们已经成功得到了Call的实例对象OkHttpCall,可调用开始调用其相关方法发起网络请求了。
OkHttpCall 这个类和okhttp就耦合的比较严重了,它就是为okhttp而生的。下面我们就分析其中最为关键的部分,也是我们最为常用的异步请求:
OkHttpCall 类
@Override public void enqueue(final Callback<T> callback) {
...
okhttp3.Call call;
Throwable failure;
synchronized (this) {
//这就是为什么我们不能使用同一个实例发起多次请求的原因,需要clone
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) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//真正发起异步请求的地方,这个call是okhttp的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.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
...
});
}
代码比较简单了,创建okhttp3.call,调用其enqueue 方法发起异步请求,处理回调结果。我们主要看关键部分
1:创建okhttp3.call使用的是call = rawCall = createRawCall();我们看一下createRawCall()的源码
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
...
return call;
}
我们知道要创建一个okhtt3.call,需要使用okhttp的Call.Factory.newCall(Request r)的方法,那个callFactory就是我们的工厂,而Request是由RequestFactory.create()的方法创建的,我们必须看一下这个方法:
RequestFactory 类
//创建了一个okhttp 的 Request,里面使用到了RequestBuilder 类,这个类负责使用RequestFactory类处理出来的信息构建http请求
okhttp3.Request create(@Nullable Object[] args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
//下面的代码比较关键,通过参数信息来完善RequestBuilder ,而这些参数信息存放在parameterHandlers里面,
//它是通过parseParameter()函数解析出来的
@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();
}
2:第二个就是如何处理返回的结果 response = parseResponse(rawResponse);
OkHttpCall类
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
//省略处理网络错误结果的代码
...
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
T body = responseConverter.convert(catchingBody);//关键代码
return Response.success(body, rawResponse);
}
将返回的okhttp3的response解析为retrofit的response。关键是是通过responseConverter将返回数据解析成我们在接口声明文件中提供的数据类型,就是那个callAdapter里面的responseType(),其是由returnType得到的,而 returnType = method.getGenericReturnType();,就是我们声明时候的泛型类型。
11. 思考
我们为什么要阅读一个优秀框架的源码呢,首先阅读其源码有助于我们更加熟练的使用此框架,但是这不应该成为我们的主要目的。我们的主要目的应该是学习其优秀的设计思想,以及其某些代码处理手段,以便于我们日后也可以写出这么优秀的东西来。
此次阅读retrofit源码,有几点印象深刻:
1:我对其callAdapter,以及Conveter上的设计感到由衷的佩服,通过这样的设计大大增强了可扩展性,就是因为这样优秀的设计才使得我们可以集成rxjava2等优秀的框架到retrofit上。:
2:大量使用了构造者模式,简化了复杂的对象生成过程。
3:其动态代理以及静态代理使用的也是恰到好处,对我既有相关知识是一个很好的增强。
4:处理注解的手法,特别是处理方法参数注解时的手法特别值得我们认真学习。
四、使用的设计模式
1. Builder模式创建Retrofit
使用场景:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://ittiger.cn")
.addConverterFactory(GsonConverterFactory.create())
.build();
上面代码的对象创建方式看着是不是似曾相识,看着很眼熟,没错,Android里面的Dialog的创建就是使用的这种方式:Builder模式
Builder模式定义
将一个复杂对象的构建与它的表示分离,使得同样的构建可以创建不同的表示
Builder模式使用场景
- 相同的方法不同的执行顺序产生不同的结果
- 多个部件都可以装配到一个对象中,但是产生的结果不同
Builder模式优缺点
优点:
不需要知道产品内部的组成细节,产品与创建过程解耦
分步组装产品,使得产品的创建过程更精细更清晰
容易扩展,新产品只需要新建一个建造者即可
缺点:
Builder模式创建的产品差异性小,使用范围受限制
不同的产品会产生多个建造者和指挥者
2. 工厂方式模式(创建CallAdapter & Converter)
本文我就已CallAdapter进行举例,看懂CallAdapter的创建原理之后,再看Converter的创建也就比较简单,都是一样的道理。
Retrofit场景
Retrofit中使用工厂方式模式的场景我在前面讲ExecutorCallAdapterFactory实现的时候已经讲过了,这里就不重复举例了,大家可以对照着源码看下。
工厂方法模式定义
一个用于创建对象的接口,让子类决定实例化哪个类
工厂方法模式使用场景
- 不需要知道其具体的类名,只需要知道生成它的工厂
- 一个类通过其子类来决定创建哪个对象
工厂方法模式优缺点
优点
只关注产品工厂即可,不需要关注产品如何创建,由工厂确定如何创建
扩展性好,新增产品时,只需要新增一个具体工厂和具体产品
缺点
新增产品时,需要新增具体工厂和具体产品类,使系统变得庞大
系统中加入抽象层,增加了系统的抽象性和理解难度
3. 适配器模式 >> CallAdapter
Retrofit场景
先来看看CallAdapter在Retrofit中的使用场景
public interface CallAdapter<T> {
public Type responseType();
public <R> Call<R> adapt(Call<R> call);
}
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
前面讲到ExecutorCallAdapterFactory会生成一个CallAdapter实例。而CallAdapter这个名字看着是不是也很眼熟,也有种似曾相识的感觉,没错,CallAdapter与我们在Android中使用ListView或RecyclerView时经常用到的各种Adapter一样也是一个适配器。
适配器模式定义
将一个类的接口变成客户端所需要的另一个接口,从而使原本因接口不匹配而无法一起工作的两个类可以在一起工作
适配器模式使用场景
1. 需要复用现有类,而现有类不符合系统需求
2. 需要一个统一的输出接口,而输入端类型不可预知
适配器模式优缺点
优点
复用性好,引入适配器类来重用适配者类,无需修改原有代码
增加类的透明性,将适配过程封装在适配器类中,对使用者来说相对透明
灵活性扩展性好,通过配置可以随时更换适配器
缺点
使用适配器会使系统整体不好把握,调的是A接口,却被适配成了B接口的实现
3. 静态代理模式 >> ExecutorCallbackCall
Retrofit场景
还是先来看看Retrofit中使用ExecutorCallbackCall的场景
//ExecutorCallAdapterFactory中生成CallAdapter实例
return new CallAdapter<Call<?>>() {
...
@Override public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
静态代理模式定义
为其他对象提供一种代理以控制对这个对象的访问
静态代理模式使用场景
无法访问或不想直接访问某个对象
静态代理的优缺点
优点
1. 协调调用者与被调用者,降低系统耦合度
2. 减小外部接口与内部接口实现的关联,降低耦合
缺点
1. 委托对象与代理对象需要实现相同的接口,当接口类增加方法时,除了所有实现类需要增加该方法外,所有代理类也需要实现此方法,增加了维护难度
2. 一个代理类只能代理一种类型的对象
4. 动态代理 >> Retrofit.create()
先看下Retrofit.create()方法的具体实现代码:
public <T> T create(final Class<T> 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 {
...
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
相信很多人在刚开始用Retrofit时都会有一点疑问,我们明明声明的是接口,为什么通过create()方法就能创建出一个对象实例呢?
通过上面的实现源码我们找到了答案,那就是使用了JDK中提供的动态代理机制,它会在运行过程中为我们声明的服务接口动态的创建出一个代理对象,以便实现我们的请求操作。我个人认为这是Retrofit框架得以实现的一个核心之处,另外一个核心之处就是其完善的注解机制,关于其注解本文就不说,主要就是一些注解的声明和解析,比较简单,感兴趣的可以去看看。
动态代理使用场景
静态代理特点一个代理对应一种类型,如果有多个类需要代理则需要多个代理,而且维护成本高,而动态代理就是来解决此类问题
动态代理特点
运行期由JVM通过反射机制动态生成,可以代理多种类型,代码复用性高。但是只能代理Java接口,不能代理Java实现类。
参考:
- https://www.jianshu.com/p/abd144912e2a
- https://blog.csdn.net/qq_29152241/article/details/82177648
- https://blog.csdn.net/shusheng0007/article/details/81335264
设计模式:
- https://blog.csdn.net/huyongl1989/article/details/52829822