一、Retrofit简介
Retrofit是由
Square公司
出品的针对于Android和Java的类型安全的Http客户端,网络服务基于
OkHttp
。
二、代码阅读前基础知识准备
在阅读Retrofit源代码前需要了解以下方面的基础知识点。
2.1 android耗时操作的处理套路
在Android进行耗时操作时,通常会将耗时任务放在子线程或线程池中执行,执行完毕后的结果再通过回调返回到主线程中,在回调过程中伴随有线程的切换。
Android中这种耗时操作的处理套路,可以参考在子线程中对UI界面中进行更新,一般使用Handler来进行回调和切换线程。
Retrofit在处理耗时的网络请求操作过程中也采用了这样的套路,只是Retrofit采用的套路比较深。Retrofit网络请求框架的基本流程如下,图下的Executor一般采用OKhttp库充当,在OKhttp模块内有线程池,可以不断接收网络请求线程。网络请求的执行结果被解析后返回,返回时一般使用Retrofit中的
defaultCallbackExecutor进行切换线程的操作。
2.2 设计模式
Retrofit在设计中采用的大量的设计模式,众多的设计模式造就了Retrofit的超级解耦和好用,下面对Retrofit采用的设计模式进行一个大致的列举和说明。
抽象工厂模式
抽象工厂模式属于创建者模型,主要是为了将用户从固定类型的创建过程中解耦出来,隐藏复杂的new操作。
Retrofit中采用的是抽象工厂模式,包括有
okhttp3.Call.Factory,CallAdapter.Factory 和 Converter.Factory。
public interface CallAdapter<T> {
Type responseType();
<R> T adapt(Call<R> call);
abstract class Factory {
public abstract 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);
}
}
}
|
Retorfit中默认有CallAdapter接口的实现,看Retrofit中的默认实现
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();
@Override
public CallAdapter<?> 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 call;
}
};
}
}
|
但是一般情况下都是用现在RxJava,所以就有了RxJavaCallAdapterFactory供我们使用。
public final class RxJavaCallAdapterFactory extends CallAdapter.Factory {
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
......
}
CallAdapter<Observable<?>> callAdapter = getCallAdapter(returnType, scheduler);
......
return callAdapter;
}
private CallAdapter<Observable<?>> getCallAdapter(Type returnType, Scheduler scheduler) {
......
return new SimpleCallAdapter(observableType, scheduler);
}
|
RxJavaCallAdapterFactory和DefaultCallAdapterFactory两个具体工厂类生产出来的产品就是SimpleCallAdapter和CallAdapter。
适配器模式
适配器模式将一个类的接口,转化成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
CallAdapter的作用是调度网络请求,在里面的adapt方法用了适配器模式,将默认的Call适配到客户端想要用的Adapter上。
外观模式(门面模式)
外观模式(门面模式)属于结构性模式,它隐藏了系统的复杂性,为子系统的一组接口提供一个统一的访问接口,这个接口使得子系统更容易被访问或使用。
Retrofit的门面就是
retrofit.create()
另外Retrofit模式还包括享元模式,装饰者模式,建造者模式,动态代理模式和策略模式等等。
三、Retrofit源码分析
一个Retrofit实例
public class LearnRetrofit {
public static final String API_URL = "https://api.github.com";
//创建接口
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<ResponseBody> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
public static void main(String[] args) throws IOException {
//创建Retrofit对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.build();
//动态生成一个代理对象
GitHub github = retrofit.create(GitHub.class);
//生成一个OKHttpCall的代理对象
Call<ResponseBody> call = github.contributors("square", "retrofit");
//返回结果
Response<ResponseBody> response = call.execute();
//打印数据
System.out.println(response.body().string());
}
}
|
3.1 源码解析之Retrofit对象的创建
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.build();
|
Retrofit中的创建代码
public Retrofit build() {
...
// 创建OkHttp,目前Retrofit只支持OkHttp
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 创建Executor,见步骤3
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
// 对adapters进行保护性拷贝,并且加入默认的call adapter(使用上面创建的Executor来构建,可以认为是把主线程中的Handler传入)
// 构建adapterFactories集合,将defaultAdapterFactory加入其中,见步骤4
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
// 对converters进行保护性拷贝
// 一般传入的为GsonConverterFactory对象,其作用主要是将json转换成java对象
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
//最终完成Retrofit对象构建
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
|
Retrofit代码的创建与两个主要任务:
- 创建callbackExecutor(内部获取主线程MainLooper来构建Hanlder,其execute方法本质是Handler.post(runnable),待用于线程切换)。
- 构建adapterFactories集合,将defaultAdapterFactory加入其中(ExecutorCallAdapterFactory类,线程切换关键实现,内部持有OkHttp代理delegate,在delegate.enqueue中的onRespond方法内使用刚刚创建的callbackExecutor.execute方法,从而实现线程切换)。
Retrofit代码创建中Executor的获取,从主线程获取Looper后创建Handler,通过Handler.post来完成线程的切换。
static class Android extends Platform {
@Override
public Executor defaultCallbackExecutor() {
// 返回MainThreadExecutor
return new Platform.Android.MainThreadExecutor();
}
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
// 从主线程得到MainLooper,构建Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
// execute方法本质:通过handler,在主线程上执行该runnable
handler.post(r);
}
}
}
|
线程切换的过程
@Override
public void enqueue(final Callback<T> callback) {
if (callback == null) throw new NullPointerException("callback == null");
// 子线程中执行,此处的delegate本质是OkHttpCall(主要用于对接OkHttp框架)
delegate.enqueue(new Callback<T>() {
@Override
public void onResponse(final Call<T> call, final Response<T> response) {
//该方法本质是调用主线程的Handler执行runnable
callbackExecutor.execute(new Runnable() {
@Override
public void run() {
if (delegate.isCanceled()) {
// Emulate OkHttp's behavior of throwing/delivering an IOException oncancellation.
callback.onFailure(call, new IOException("Canceled"));
} else {
callback.onResponse(call, response);
}
}
});
}
@Override public void onFailure(final Call<T> call, final Throwable t) {
// 包裹用户传入的callback,从而实现线程切换
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(call, t);
}
});
}
});
}
|
3.2 创建接口实现类 Retrofit.create(Api.class)
创建并返回一个会拦截接口方法的动态代理对象实例,接口方法被调用时,会被其拦截,内部将接口方法适配成HTTP Call,再构造对应的OKHttpCall,这里的OKHttpCall是OKHttp的一个包装类,用它生成OkHttp。最后通过CallAdapter.adapt()转换成Retrofit适用的call delegares(即 ExecutorCallbackCall)。
Api api = retrofit.create(Api.class);
// create方法内部实现,返回一个动态代理实例
public <T> T create(final Class<T> service) {
...
// 该动态代理会对接口方法进行拦截
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
// 创建一个InvocationHandler,接口方法被调用时会被拦截调用
new InvocationHandler() {
private final Platform platform = Platform.get();
// 当Api接口方法被调用时,会调用invoke方法拦截
@Override public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
...
// 通过解析api方法注解、传参,将接口中方法适配成HTTP Call,详解见步骤6
ServiceMethod serviceMethod = loadServiceMethod(method);
// 拦截下来之后,内部构建一个okHttpCall
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
// 最后通过callAdapter将okHttpCall转换成为Retrofit适用的call delegates(代理),
Android平台默认使用ExecutorCallAdapterFactory,adapt返回ExecutorCallbackCall
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
|
上述
ServiceMethod 内部主要是将方法中的注解取出,转换成HTTP Call的逻辑,暂且不深究。
3.3 执行http请求
在示例代码中调用call.execute()就会执行http请求,这里的call是OKHttpCall的一个对象。从下面的代码可见,调用了OKHttpCall.execute(),该方法会生成一个okhttp3.Call将任务抛给OKHttp,完了调用parseResponse,用Converter将okhttp3.Response转换成我们在范型中指定的类型Response<ResponseBody> response = call.execute(),我指定了okhttp3.ResonseBody。然后返回结果。如果我在构造Retrofit时提供了GsonConverter,addConverterFactory(GsonConverterFactory.create())那么上面的T body = responseConverter.convert(catchingBody);responseConverter就是GsonConverter。
final class OkHttpCall<T> implements Call<T> {
//核心成员变量
private final okhttp3.Call.Factory callFactory;
private final RequestFactory requestFactory;
private final Object[] args;
private final Converter<ResponseBody, T> responseConverter;
//核心方法
@Override public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
if (creationFailure != null) {
if (creationFailure instanceof IOException) {
throw (IOException) creationFailure;
} else {
throw (RuntimeException) creationFailure;
}
}
call = rawCall;
if (call == null) {
try {
//将任务抛给OKHttp
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
if (canceled) {
call.cancel();
}
//转换结果
return parseResponse(call.execute());
}
//生成okhttp3.Call
private okhttp3.Call createRawCall() throws IOException {
//这个callFactory就是OKHttpClient
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
//将okhttp3.Response转换成Response
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
// Remove the body's source (the only stateful object) so we can pass the response along.
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
int code = rawResponse.code();
if (code < 200 || code >= 300) {
try {
// Buffer the entire body to avoid future I/O.
ResponseBody bufferedBody = Utils.buffer(rawBody);
return Response.error(bufferedBody, rawResponse);
} finally {
rawBody.close();
}
}
if (code == 204 || code == 205) {
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
//这个responseconverter就是默认提供的RequestBodyConverter,当然我们可以替换成自己的converter比如GsonConverter
T body = responseConverter.convert(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;
}
}
|
四、Retrofit流程总结
1.
Retrofit对象的构建 Retrofit.Builder()...build():①构建OkHttpClient,目前Retrofit仅支持OkHttpClient;②构建Executor:优先根据用户提供的callBackExcecutor来构建,若用户没有提供,则提供defaultCallbackExecutor(其内部会获取MainLooper构建handler,execute方法直接handler.post(runnable),实现在主线程上的操作);③使用executor来构建adapterFactories集合,优先将用户提供的adapterFactory加入到其中,再加上defaultCallAdapterFactory(传入②创建的callbackExecutor,defaultCallAdapterFactory内部持有OkHttpCall,在其enqueue方法中的onResponse方法调用defaultCallbackExecutor.execute方法,从而实现线程切换操作);④最终使用Retrofit构造方法构建Retrofit实例对象
2.
Retrofit接口方法的实现方式 retrofit.create(接口名.class):①create方法创建并返回动态代理对象实例,动态代理对象内部会拦截接口方法的调用②动态代理内部通过ServiceMethod将接口方法适配成HTTP Call,再构造对应的OkHttpCall,最后通过CallAdapter转换成Retrofit适用的call delegate(ExecutorCallbackCall)。
3.
使用动态代理(接口实现类)调用接口方法得到Call、使用call.enqueue进行异步请求:①调用接口方法时,动态代理对象(接口实现类)内部拦截;②调用call.enqueue,内部会调用ExecutorCallAdapter的enqueue方法,enqueue中onResponse方法调用defaultCallbackExecutor.execute方法,使用主线程Handler.post(runnable)从而实现线程切换操作。