目录
- Retrofit 简介
- Retrofit 的具体使用
- 重点分析
Retrofit 简介
Retrofit 是 Square 推出的 HTTP 框架,主要用于 Android 和 Java。Retrofit 将网络请求变成方法的调用,使用起来非常简洁方便。
- Retrofit adapts a Java interface to HTTP calls by using annotations on the declared methods to
- define how requests are made. Create instances using {@linkplain Builder
- the builder} and pass your interface to {@link #create} to generate an implementation.
这是源码开头的解释,大致意思是 Retrofit 利用方法上的注解接口转化成一个 HTTP 请求。
Retrofit 的使用
- 首先建立API接口类:
public interface ZhihuApi {
String HOST = "http://news-at.zhihu.com/api/";
@GET("4/news/latest")
Call<ZhihuList> getZhihuListNews(int page);
}
- 具体使用过程:
// 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ZhihuApi.HOST)
.addConverterFactory(GsonConverterFactory.create())
.build();
// 生成接口实现类
ZhihuApi zhihuApi = retrofit.create(ZhihuApi.class);
// 调用接口定义的请求方法,并且返回 Call 对象
Call<ZhihuList> call = zhihuApi .getZhihuListNews(1);
// 调用 Call 对象的异步执行方法
call.enqueue(Callback callback)
以上就是 Retrofit 的基础用法,注意这里的
addConverterFactory()
方法,它是用于吧返回的 http response 转换成 Java 对象,对应方法的返回值就是ZhihuList
这个自定义的类。大致流程就是获得retrofit
对象之后,接着调用create()
方法创建 ZhihuApi 的实例,然后调用 ZhihuApi 的方法请求网络,返回的是一个Call
对象,然后就可以使用Call
方法的enqueue
或者execute
来执行发起请求,enqueue
是是异步执行,而execute
是同步执行。
Retrofit 的重点解析
- Retrofit 的创建( Builder 模式)
// 用于缓存解析出来的方法
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
// 请求网络的 OKHttp 的工厂,默认是 OkHttpClient
private final okhttp3.Call.Factory callFactory;
// baseurl
private final HttpUrl baseUrl;
// 请求网络得到的 response 的转换器的集合 默认会加入 BuiltInConverters
private final List<Converter.Factory> converterFactories;
// 把 Call 对象转换成其它类型,如 Call 以及 Observer
private final List<CallAdapter.Factory> adapterFactories;
// 用于执行回调 Android 中默认是 MainThreadExecutor
private final Executor callbackExecutor;
// 是否需要立即解析接口中的方法
private final boolean validateEagerly;
以上是几个 Retrofit
中比较关键的变量,每个都有注释,一看便知。接下来看一看 内部类 Builder
的 build()
方法:
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
// 默认创建一个 OkHttpClient
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
// Android 中返回的是 MainThreadExecutor
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//adapterFactories 把 Call 对象转换成其他对象,如 Observer
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
// 请求网络得到的 response 的转换器的集合
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
}
以上代码可以看出:callAdapter
是请求返回的对象,Converter
是转换器,转换请求的响应到对应的实体对象,OkHttpClient
是具体的 OkHttp 的请求客户端,在创建 Retrofit 的时候,如果没有指定 OkHttpClient
,会创建一个默认的。如果没有指定 callbackExecutor
,会返回平台默认的,在 Android 中是 MainThreadExecutor
,并利用这个构建一个 CallAdapter
加入 adapterFactories
。
- Create() 方法
有了 Retrofit 对象后,便可以通过create()
方法创建网络请求接口类的对象。直接上代码:
public <T> T create(final Class<T> service) {
// 检查传入的类是否为接口并且无继承
Utils.validateServiceInterface(service);
if (validateEagerly) {
// 提前解析方法
eagerlyValidateMethods(service);
}
// 重点是这里
// 首先会返回一个利用代理实现的 ZhihuApi 对象
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);
}
// 为了兼容 Java8 平台,Android 中不会执行
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 解析方法 这里用到了注解(Runtime)
ServiceMethod serviceMethod = loadServiceMethod(method);
// 将刚刚解析完毕包装后的具体方法封装成 OkHttpCall ,你可以在该实现类找到 okhttp 请求所需要的参数
// 所以它是用来跟 okhttp 对接的。
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 将以上我们封装好的 call 返回给上层,这个时候我们就可以执行 call 的同步方法或者异步进行请求。
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
这里使用的是 动态代理模式 ,简单的描述就是Proxy.newProxyInstance
根据传进来的 Class 对象生成了代理类,当这个代理类执行某个方法时总是会调用 InvocationHandler
(Proxy.newProxyInstance 中的第三个参数) 的invoke
方法,在这个方法中可以执行一些操作(这里是解析方法的注解参数等),通过这个方法真正的执行我们编写的接口中的网络请求。我们再来理一下思路:
Create()
-->
return (T) Proxy.newProxyInstance(...){...}
-->
Call<ZhihuList> call = zhihuApi .getZhihuListNews(1);
-->
public Object invoke(...){...}
调用代理类的invoke()
。
记住动态代理,是在方法调用时才会真正的触发过程。
- ServiceMethod
下面看一下在invoke
中解析网络请求方法的几行,ServiceMethod serviceMethod = loadServiceMethod(method);
代码如下:
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
// 从缓存中获取该方法
result = serviceMethodCache.get(method);
if (result == null) {
// 为空就创建并且加入缓存
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
Retrofit 有一个双链表用来缓存方法
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
避免一个网络请求在多次调用的时候频繁的解析注解,毕竟注解解析过程消耗比较大。这个部分重点在ServiceMethod.Builder(this, method).build();
build()
源码很长,只截取重点:
// 用来发送请求的 client
callAdapter = createCallAdapter();
...
// 结果的转换器(Gson,FastJson …)之类
responseConverter = createResponseConverter();
// 遍历解析注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
...省略代码
- OkHttpCall
在得到 ServiceMethod
对象后,把它连同方法调用的相关参数传给了 OkHttpCall
对象,就是前面的这行代码:
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
这个OkHttpCall才是真正OkHttp请求的回调,但是针对我们使用的不同的回调,比如:RxJava的Observable、Call,所以有一层转换的关系,把OkHttpCall转成对应的Observable和Call。就是serviceMethod.callAdapter.adapt(okHttpCall)的工作。
请求方法参数,请求客户端,返回值转换,我们都定义好了之后,便完成最后一步,构建好适合请求客户端的请求方法,Retrofit 默认的是 okhttpCall 。接下来把 OkHttpCall
传给 serviceMethod.callAdapter
对象
那么CallAdapter
是干嘛的呢?上面调用了adapt
方法,它是为了把一个Call
转换成另一种类型,比如当 Retrofit 和 RxJava 结合使用的时候,接口中方法可以返回 Observable<T>
,这里相当于适配器模式。默认情况下得到的是一个 Call
对象,它是ExecutorCallbackCall
,代码如下:
@Override
public CallAdapter<Call<?>> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
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.Factory
,可以看到adapt()
方法接受一个Call对象,看下ExecutorCallbackCall
的部分源码:
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) {
if (callback == null) throw new NullPointerException("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);
}
}
});
}
...省略
}
在 enqueue
方法中,调用了 OkHttpCall
的enqueue
,所以这里相当于静态的代理模式。OkHttpCall
中的 enqueue
其实又调用了原生的OkHttp
中的 enqueue
,这里才真正发出了网络请求,部分代码如下:
@Override public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
//真正请求网络的 call
okhttp3.Call call;
Throwable failure;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
//省略了部分发代码
...
call = rawCall;
//enqueue 异步执行
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
//解析数据 会用到 conveterFactory,把 response 转换为对应 Java 类型
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();
}
}
});
}
OkHttp 获取数据后,解析数据并回调callback响应的方法,一次网络请求便完成了。