版权声明:本文为博主原创文章,未经博主允许不得转载
Github:github.com/Darkwh
若有错误或疑问欢迎小伙伴们留言评论
友情提示!!!
本人英文渣,文章中哪些单词翻译的不够形象的话。。。。那你到是来打我呀O(∩_∩)O
系列回顾
文章目录

前言
相信大多数Android开发者都听过并使用过Retrofit,一款由square公司开源的网络请求库。自己也用了一段时间,retrofit在okhttp的基础上再一次简化我们的网络请求操作,并且支持rxjava,用起来更加的得心应手。今天给大家分享一下自己阅读retrofit源码的成果,记录的同时希望也能将收获分享给大家,个人水平有限,有错误的地方也请大神包涵和指正。
Retrofit的基本使用
Retrofit的使用方法网上资料很多,这里不多说了,简单贴一下使用方法,以后的分析源码会跟着调用顺序去走。
创建接口文件
interface TestService{
@GET("data/Android/10/1")
fun getMsg(): Call<MsgBean>
}
创建接收网络请求的实体类
class MsgBean {
var error: Boolean = false
}
创建Retrofit对象
val retrofit: Retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("http://gank.io/api/")
.build()
创建接口的代理对象
val service: TestService = retrofit.create(TestService::class.java)
获取Call对象
val call: Call<MsgBean> = service.getMsg()
执行请求并监听返回结果
call.enqueue(object : Callback<MsgBean> {
override fun onFailure(call: Call<MsgBean>?, t: Throwable?) {
Log.i("wh", "onFailure")
}
override fun onResponse(call: Call<MsgBean>?, response: Response<MsgBean>?) {
Log.i("wh", "onResponse")
}
})
源码目录结构及项目组成
源码目录
retrofit的源码类比较少,非常适合新手阅读(比如我),其中http包下面都是一些自定义的注解(@GET、@POST等),这里就不一一列出了

比较重要的几个类
接口:Call、CallAdapter、Converter、Callback
类:Retrofit、ServiceMethod、ParameterHandler、OkHttpCall
接下来让我们了解一下这几个类大致是做什么的,首先我们从接口开始,因为接口属于高度抽象,了解接口的定义有助于我们理解源码。
1.Call
/**
* An invocation of a Retrofit method that sends a request to a webserver and returns a response.
* Each call yields its own HTTP request and response pair. Use {@link #clone} to make multiple
* calls with the same parameters to the same webserver; this may be used to implement polling or
* to retry a failed call.
*
* <p>Calls may be executed synchronously with {@link #execute}, or asynchronously with {@link
* #enqueue}. In either case the call can be canceled at any time with {@link #cancel}. A call that
* is busy writing its request or reading its response may receive a {@link IOException}; this is
* working as designed.
*
* @param <T> Successful response body type.
*/
public interface Call<T> extends Cloneable {
......
}
一个向服务器发送请求并获得响应的调用器,主要的方法为
Response<T> execute() throws IOException;
void enqueue(Callback<T> callback);
这两个方法小伙伴们应该很熟悉了,execute是发送同步请求,enqueue是发送异步请求
2.CallAdapter
/**
* Adapts a {@link Call} with response type {@code R} into the type of {@code T}. Instances are
* created by {@linkplain Factory a factory} which is
* {@linkplain Retrofit.Builder#addCallAdapterFactory(Factory) installed} into the {@link Retrofit}
* instance.
*/
public interface CallAdapter<R, T> {
......
}
中文意思大致就是说CallAdapter接收一个Call对象(带着返回类型参数R)并转换为新的类型T。CallAdapter会被 Retrofit.Builder.addCallAdapterFactory(Factory)指定的Factory创建(注意builder可以指定多个Factory的,后面会说明这个问题)
上面的文字可能会让你觉得比较乱,没关系我们来看一下这个接口中的其中一个抽象方法:
T adapt(Call<R> call);
这个方法就是CallAdapter最为核心的一个方法,如同注释中的描述一样,接收一个Call对象,Call对象带着参数R,方法返回T类型。
再看CallAdapter接口中的另一个方法:
Type responseType();
代码中的注解描述为:当把HTTP返回体转换为JAVA类的时候返回参数类型,例如你得自定义接口中的方法返回值为Call<Foo>,那么Type类型则为Foo。
总结来说CallAdapter将Call<R> 转换为T的这么一个转换适配器
CallAdapter接口中还有一个内部工厂类:
abstract class Factory {
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
典型的工厂模式,通过get方法来获取CallAdapter实例
3.Converter
/**
* Convert objects to and from their representation in HTTP. Instances are created by {@linkplain
* Factory a factory} which is {@linkplain Retrofit.Builder#addConverterFactory(Factory) installed}
* into the {@link Retrofit} instance.
*/
public interface Converter<F, T> {
......
}
Converter接口的作用是将Java实体类和Http内容相互转换
同CallAdapter一样,Converter接口中也有一个内部工厂类:
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
protected static Type getParameterUpperBound(int index, ParameterizedType type) {
return Utils.getParameterUpperBound(index, type);
}
protected static Class<?> getRawType(Type type) {
return Utils.getRawType(type);
}
}
- responseBodyConverter方法将Http内容转换为Java实体
- requestBodyConverter方法将Java实体转换为Http内容(RequestBody)
4.Callback
public interface Callback<T> {
void onResponse(Call<T> call, Response<T> response);
void onFailure(Call<T> call, Throwable t);
}
网络请求成功/失败的回调接口,不多说了吧就。
以上为Retrofit源码中的四个接口及其简单介绍。接下来让我们再了解一下其他几个比较重要的类
1.Retrofit
就这个名字,和项目名同款,意味这个类的地位是多么重要,具体代码后面分析。
2.ServiceMethod
/**
* Adapts an invocation of an interface method into an HTTP call.
*/
final class ServiceMethod<R, T> {
......
}
将一个接口方法转换为HTTP请求的调用器
非常核心的一个类,它的作用同源码中的注释一样,会将你定义的接口中的方法转换为Http请求。具体的代码我们同样放到后面分析。
3.ParameterHandler
这个类源码没什么注释,故名思议是处理参数的,这里处理的是请求参数。
ParameterHandler的定义如下
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
final ParameterHandler<Iterable<T>> iterable() {
return new ParameterHandler<Iterable<T>>() {
@Override void apply(RequestBuilder builder, @Nullable Iterable<T> values)
throws IOException {
if (values == null) return; // Skip null values.
for (T value : values) {
ParameterHandler.this.apply(builder, value);
}
}
};
}
final ParameterHandler<Object> array() {
return new ParameterHandler<Object>() {
@Override void apply(RequestBuilder builder, @Nullable Object values) throws IOException {
if (values == null) return; // Skip null values.
for (int i = 0, size = Array.getLength(values); i < size; i++) {
//noinspection unchecked
ParameterHandler.this.apply(builder, (T) Array.get(values, i));
}
}
};
}
}
ParameterHandler是一个抽象类,拥有一个抽象方法apply和两个遍历方法,两个遍历方法分别适用于Iterable 和数组,遍历集合(数组)并执行apply方法。
ParameterHandler有许多的子类,我们来看其中的几个:
static final class RelativeUrl extends ParameterHandler<Object> {
@Override void apply(RequestBuilder builder, @Nullable Object value) {
checkNotNull(value, "@Url parameter is null.");
builder.setRelativeUrl(value);
}
}
static final class Header<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
Header(String name, Converter<T, String> valueConverter) {
this.name = checkNotNull(name, "name == null");
this.valueConverter = valueConverter;
}
@Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
if (value == null) return; // Skip null values.
String headerValue = valueConverter.convert(value);
if (headerValue == null) return; // Skip converted but null values.
builder.addHeader(name, headerValue);
}
}
static final class Part<T> extends ParameterHandler<T> {
private final Headers headers;
private final Converter<T, RequestBody> converter;
Part(Headers headers, Converter<T, RequestBody> converter) {
this.headers = headers;
this.converter = converter;
}
@Override void apply(RequestBuilder builder, @Nullable T value) {
if (value == null) return; // Skip null values.
RequestBody body;
try {
body = converter.convert(value);
} catch (IOException e) {
throw new RuntimeException("Unable to convert " + value + " to RequestBody", e);
}
builder.addPart(headers, body);
}
}
不难看出,ParameterHandler作用就是为RequestBuilder构建参数,RequestBuilder是retrofit源码中的一个累,其build方法会返回一个Request对象,Request对象是OkHttp中的类,没看过,就不分(装)析(逼)了。
不知道小伙伴们有没有注意到Part(Headers headers, Converter<T, RequestBody> converter)这行代码,这就是前面说的Converter接口其中一个作用,将Java对象转换为Http内容。
3.OkHttpCall
这是Retrofit中对Call接口内置的默认实现,这个类其实并没有Retrofit和ServiceMethod重要,考虑是默认实现,所以也会着重分析一下,来让我们SOLO下代码:
嗯。。。代码有点多,就不贴了,还是来让我们看看其中比较重要的几个变量和方法吧:
private final ServiceMethod<T, ?> serviceMethod;
private @Nullable
okhttp3.Call rawCall;
OkHttpCall对象持有一个ServiceMethod引用和一个okhttp3.Call引用
再看OkHttpCall的其他方法,这里我们主要看一下enqueue异步请求方法,其它代码小伙伴们可自行研究:
@Override
public void enqueue(final Callback<T> callback) {
//检查传入的Callback是否为空,为空抛出异常
checkNotNull(callback, "callback == null");
okhttp3.Call call;
Throwable failure;
synchronized (this) {
//此OkHttpCall对象如果执行过,再次调用会抛出异常
//一般不会抛这个异常,因为每次都是创建一个新的OkHttpCall对象
//所以源代码中并没有executed=false这种设置,只有executed = true
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
//此处创建原始的Call对象
call = rawCall = createRawCall();
} catch (Throwable t) {
//如果为指定的三种异常,则抛出异常(为RxJava支持)
throwIfFatal(t);
//变量赋值
failure = creationFailure = t;
}
}
}
if (failure != null) {
//回调给用户设置的匿名接口
callback.onFailure(this, failure);
return;
}
if (canceled) {
call.cancel();
}
//调用OkHttp的Call对象的enqueue方法
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) {
//如有解析异常则回调给callback
callFailure(e);
return;
}
callSuccess(response);
}
@Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
}
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方法总结来说是首先创建一个原始的Call对象(注意这里为okhttp3的Call对象),然后调用Call.enqueue方法,并对返回结果进行解析,请求出错或者解析出错会回调到你设置的Callback对象中的onFailure方法,解析成功则会回调callSuccess方法
来看一下创建原始Call对象的方法定义:
private okhttp3.Call createRawCall() throws IOException {
Request request = serviceMethod.toRequest(args);
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
通过ServiceMethod的toRequest方法构造出一个Request队形,然后通过指定的callFactory来创建call对象并返回。这里默认的callFactory前面讲解Retrofit.Builder的build方法中有介绍,未指定的时候默认使用OkHttpClient。
看一下toRequest方法的定义:
/**
* Builds an HTTP request from method arguments.
*/
Request toRequest(@Nullable Object... args) throws IOException {
RequestBuilder requestBuilder = new RequestBuilder(httpMethod, baseUrl, relativeUrl, headers,
contentType, hasBody, isFormEncoded, isMultipart);
@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();
}
这个方法的作用就是通过遍历上面介绍过的ParameterHandler数组并调用apply函数将方法中的参数转换成Http请求参数。
再来看一下解析返回结果的方法定义:
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
......
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//解析参数
T body = serviceMethod.toResponse(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
// If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught();
throw e;
}
}
其中会调用ServiceMethod.toResponse,稍微跟一下:
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}
可以看到此处使用你指定的Convert来对响应数据进行转换(比如我们最常用的json转实体类)
总结
以上为大家介绍了一下retrofit的基本使用和几个重要的类,下一篇我将按照retrofit使用的顺序来分析一下源码,将我说理解的内容分先给大家,如有错误的地方还请包涵和指正!勿喷!!!