Retrofit2.1源码解析
标签(空格分隔): java android 网络请求 retrofit OkHttp
首先附上《Retrofit2源码解析》原文链接:http://bxbxbai.github.io/2015/12/13/retrofit2/
基于《Retrofit2源码解析》,本文主要在retrofit更新到2.1版本后,其中源码稍有改动的地方做了一些补充,并以《Retrofit2源码解析》的文章结构重新梳理了Retrofit的相关知识以及对于使用时的注解介绍。
本文只是retrofit2.0与2.1版本中的区别介绍,顺便将自己看源码时本人理解的代码注释记录一下,作为学习心得。
一、Retrofit是什么
A type-safe HTTP client for Android and Java.
它是一个HTTP请求工具
二、Retrofit怎么用
链接:http://bxbxbai.github.io/2015/12/13/retrofit2/
本人觉得上述文章关于如何简单使用retrofit的内容简单易懂,各位读者可以直接看,本文就不多说重复的内容了。下面主要列举一些开发中常用到的请求方式的写法。
三、Retrofit请求方式注解类型
- 简单的GET、POST请求
- 添加参数(header)请求
- 表单类型的请求
- Multipart(文件上传)类型的请求
- 文件下载
四、Retrofit原理
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
1.这是创建retrofit对象的方法,我们就进去build()方法中一看究竟。
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
build()方法中,做了这几件事情:
1.创建OKHttpClient
2.创建callBackExecutor
3.创建List<CallAdapter.Factory>
4.创建List<Converter.Factory>
5.调用Retrofit的构造方法,创建Retrofit对象
WeatherService service = weatherRetrofit.create(WeatherService.class);
2.调用retrofit对象的create()方法,创建一个动态代理的对象(“服务”的接口)。
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);//验证外部传进的“服务”接口是否合法
if (validateEagerly) {//根据validateEagerly判断是否对接口中的全部方法进行缓存
eagerlyValidateMethods(service);
}
//使用Proxy工厂类返回一个泛型实例。
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 {
// 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);//java8出现default修饰符,这里retrofit就直接invoke default method
}
ServiceMethod serviceMethod = loadServiceMethod(method);//加载调用的方法
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);//将方法中的参数和调用方法构建出一个OKHttpCall
return serviceMethod.callAdapter.adapt(okHttpCall);//将构建好的OKHttpCall通过serviceMethod中的CallAdapter发送出去
}
});
}
//加载方法,可以看出将传进来的method放在了LinkMap中进行缓存,取得时候先从缓存中取
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();//创建ServiceMethod,进去build()方法中去看看
serviceMethodCache.put(method, result);
}
}
return result;
}
//首先创建了callAdapter
public ServiceMethod build() {
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?");
}
//创建responseConverter
responseConverter = createResponseConverter();
//循环遍历方法中的注解,进行解析
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
//如果缺少请求方式的注解,则抛出error
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
//以下代码就不一一翻译了。。。
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
//以下代码功能是获取参数的个数,进行遍历,判断参数的注解类型是否规范,不规范抛出error,将参数根据注解类型进行解析。
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
if (relativeUrl == null && !gotUrl) {
throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
}
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError("Non-body HTTP method cannot contain @Body.");
}
if (isFormEncoded && !gotField) {
throw methodError("Form-encoded method must contain at least one @Field.");
}
if (isMultipart && !gotPart) {
throw methodError("Multipart method must contain at least one @Part.");
}
return new ServiceMethod<>(this);
}
createCallAdapter()这个方法中,跟进源代码中可以看到:
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
……
int start = adapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = adapterFactories.size(); i < count; i++) {
CallAdapter<?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
……
}
3.CallAdapter的作用,就是将Call对象转化为另一个对象,可能是为了支持RxJava才设计这个类。
createResponseConverter()这个方法中,创建了Converter< F,T >,跟进源码中:
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(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) {
//noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
……
}
4.这个接口主要的作用就是将HTTP返回的数据解析成Java对象,主要由Xml、Gson、protobuf等等,你可以在创建Retrofit对象时添加你需要使用的Converter实现。
Call<CityListBean> call = service.listCity("北京");
刚才通过create创建的动态代理对象,当执行listCity时,将会返回一个OKHttpCall对象(从源码中可以看到Retrofit默认使用OKHttpCall),根据这个Call对象才能开始执行Http请求。
call.enqueue(new Callback<CityListBean>() {
@Override
public void onResponse(Call<CityListBean> call, Response<CityListBean> response) {
}
@Override
public void onFailure(Call<CityListBean> call, Throwable t) {
}
});
或者
Response<BaseBean> response = baseBeanCall.execute();
执行请求方法有两种,前者是异步请求,后者是同步请求。进入enqueue方法中一看究竟:
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
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) {
failure = creationFailure = t;
}
}
}
if (failure != null) {
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
@Override public void onFailure(okhttp3.Call call, IOException e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callFailure(Throwable e) {
try {
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
t.printStackTrace();
}
}
private void callSuccess(Response<T> response) {
try {
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
}
从源码中可以看出,enqueue中实际的网络请求操作是使用OKHttp中得Dispatcher.enqueue(),(往下的源码跟进就不属于本文中得范畴,读者有兴趣可以看看OKHttp的源码),请求返回的数据,通过CallBack返回给调用者。
5.CallBack这个接口中只有两个方法:
void onResponse(Call<T> call, Response<T> response);
void onFailure(Call<T> call, Throwable t);
五、结束语
至此,Retrofit的源码分析到这就结束了,感谢本文多次提到的《Retrofit2源码解析》的作者,让我在分析源码的过程中屡屡受益!本文内容均是个人对源码的理解,在表述上可能存在缺陷,请各位读者多多提出宝贵建议。