retrofit
版权申明】非商业目的可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/81335264
出自:shusheng007
- 前言
- 概述
- retrofit 用法
- Retrofit源码详细分析
- 思考
- 总结
前言
Android开发发展到现在,网络请求的主流已经毫无疑问的是Retrofit
加okhttp
了,两年前就使用了Retrofit,但是一直没有仔细研究其源码,前段时间系统梳理了java注解的知识集结成 秒懂 Java注解类型(@Annotation)一文后,就想看一下优秀框架如何使用注解的,刚好Retrofit大量使用了注解,所以花了3天时间仔细研究了一下。
Retrofit由于源码较少,非常适合初次阅读框架源码的同学,但是需要具备Http及Java注解和反射的知识。
概述
Retrofit
是一个封装了Okhttp
网络请求库的优秀框架,其可以轻松提供Restful
风格的接口,这是它的官方地址 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源码详细分析
本文使用的是retrofit
2.4.0 版本,在读源码的时候发现了一个问题,就是从GitHub
拷贝的源码,与直接通过gradle
引入Android
项目然后在AndroidStudio
的类库查看的代码有出入,AndroidStudio
中看少了两个类,这两个类被合并了,如下图所示:
关键接口
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
请求回调,一个成功,一个失败,这个没有什么好说的。
关键类:
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
请求的地方,上面的所有类都是为它服务。
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
,然后我们就可以发起网络请求相关操作了。
获得接口代理
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
中,包括构建以及起调。
构建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);
}
构建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 需要赋值。
获取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就是它。
获取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实例,我们可以愉快的调用它的实例函数啦。
调用函数
还记得我们的出发点吗?就是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<Object>
类型的参数,我们传入的是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。这样代理就有能力在执行被代理对象的动作是附加一些动作了,例如这里的线程切换。妙哉否?妙哉!
发起请求
至此我们已经成功得到了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();
}
这个方法可以说是至关重要,我们前面搞来搞去就是为了能生成一个okhttp3的一个Request。
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();
,就是我们声明时候的泛型类型。
思考
我们为什么要阅读一个优秀框架的源码呢,首先阅读其源码有助于我们更加熟练的使用此框架,但是这不应该成为我们的主要目的。我们的主要目的应该是学习其优秀的设计思想,以及其某些代码处理手段,以便于我们日后也可以写出这么优秀的东西来。
此次阅读retrofit
源码,有几点印象深刻:
1:我对其callAdapter
,以及Conveter
上的设计感到由衷的佩服,通过这样的设计大大增强了可扩展性,就是因为这样优秀的设计才使得我们可以集成rxjava2
等优秀的框架到retrofit
上。:
2:大量使用了构造者模式,简化了复杂的对象生成过程。
3:其动态代理以及静态代理使用的也是恰到好处,对我既有相关知识是一个很好的增强。
4:处理注解的手法,特别是处理方法参数注解时的手法特别值得我们认真学习。
总结
这是我初次完整分析一个框架源码,以前都是局部查看,这就注定了很难全盘把握作者的设计思想。这种事情自己觉得有时间可以长做,最好可以参与到其中。
与此博客相关的文章:用Retrofit+RxJava2封装优雅的网络请求框架也值得一读。
相关阅读
muduo是个基于现代C++高效的高并发网络库,他依赖boost库,由陈硕大神编写,更多详情介绍,请看点击打开链接 muduo代码结构比较清晰易懂,
网上打字赚钱是真的吗?经常有网友问我这个问题,真真假假我也做过不少分析,相信很多人都看过。对于这个老生常谈的问题,就算分析的再怎
刚刚喝了一波毒鸡汤,其中印象最深的就是这两个: 没有人能够让你放弃梦想,自己想想就放弃了。 找对象的时候不能光看对方的外表。。。
代码地址如下:http://www.demodashi.com/demo/14960.html 项目简介 H5DS (HTML5 Design software) 这是一款基于WEB的 H5制作工具
想让uC/OS-Ⅱ管理用户的任务,用户必须要先建立任务。用户可以通过传递任务地址和其它参数到以下两个函数之一来建立任务:OSTaskCr