本文转载自Carson_Ho的文章:手把手带你深入剖析 Retrofit 2.0 源码
前言
- 在
Andrroid
开发中,网络请求十分常用 - 而在
Android
网络请求库中,Retrofit
是当下最热的一个网络请求库
我们先来看Builder类
请按下面提示的步骤进行查看
<-- Builder类-->
public static final class Builder {private Platform platform;private okhttp3.Call.Factory callFactory;private HttpUrl baseUrl;private List converterFactories &#61; new ArrayList<>();private List adapterFactories &#61; new ArrayList<>();private Executor callbackExecutor;private boolean validateEagerly;
<-- 步骤1 -->
public Builder() {this(Platform.get());
}
...
}<-- 步骤2 -->
class Platform {private static final Platform PLATFORM &#61; findPlatform();static Platform get() {return PLATFORM; }<-- 步骤3 -->
private static Platform findPlatform() {try {Class.forName("android.os.Build");if (Build.VERSION.SDK_INT !&#61; 0) {return new Android(); }} catch (ClassNotFoundException ignored) {}try {Class.forName("java.util.Optional");return new Java8();} catch (ClassNotFoundException ignored) {}try {Class.forName("org.robovm.apple.foundation.NSObject");return new IOS();} catch (ClassNotFoundException ignored) {}
return new Platform();}
...
}<-- 步骤4 -->
static class Android extends Platform {&#64;OverrideCallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {return new ExecutorCallAdapterFactory(callbackExecutor);}&#64;Override public Executor defaultCallbackExecutor() {return new MainThreadExecutor();}static class MainThreadExecutor implements Executor {private final Handler handler &#61; new Handler(Looper.getMainLooper());&#64;Override public void execute(Runnable r) {handler.post(r);}}
}
<-- 步骤5 -->
public Builder(Platform platform) {this.platform &#61; platform;
converterFactories.add(new BuiltInConverters());
}
对Builder类分析完毕&#xff0c;总结&#xff1a;Builder设置了默认的
特别注意&#xff0c;这里只是设置了默认值&#xff0c;但未真正配置到具体的Retrofit类的成员变量当中
步骤3
步骤1&#xff1a;ServiceMethod类
构造函数
<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory;
final CallAdapter> callAdapter;
private final Converter responseConverter;
private final HttpUrl baseUrl;
private final String relativeUrl;
private final String httpMethod;
private final Headers headers;
private final MediaType contentType; private final ParameterHandler>[] parameterHandlers; <-- ServiceMethod 类的构造函数 -->
ServiceMethod(Builder builder) {this.callFactory &#61; builder.retrofit.callFactory(); this.callAdapter &#61; builder.callAdapter; this.responseConverter &#61; builder.responseConverter; this.baseUrl &#61; builder.retrofit.baseUrl(); this.relativeUrl &#61; builder.relativeUrl; this.httpMethod &#61; builder.httpMethod; this.headers &#61; builder.headers; this.contentType &#61; builder.contentType; . this.hasBody &#61; builder.hasBody; y this.isFormEncoded &#61; builder.isFormEncoded; this.isMultipart &#61; builder.isMultipart; this.parameterHandlers &#61; builder.parameterHandlers;
}
步骤2&#xff1a;ServiceMethod的Builder&#xff08;
public Builder(Retrofit retrofit, Method method) {this.retrofit &#61; retrofit;this.method &#61; method;this.methodAnnotations &#61; method.getAnnotations();this.parameterTypes &#61; method.getGenericParameterTypes(); this.parameterAnnotationsArray &#61; method.getParameterAnnotations(); }
步骤3&#xff1a;ServiceMethod的build&#xff08;&#xff09;
public ServiceMethod build() {callAdapter &#61; createCallAdapter(); responseType &#61; callAdapter.responseType(); responseConverter &#61; createResponseConverter(); for (Annotation annotation : methodAnnotations) {parseMethodAnnotation(annotation);}int parameterCount &#61; parameterAnnotationsArray.length;parameterHandlers &#61; new ParameterHandler>[parameterCount];for (int p &#61; 0; p
- 当选择了RxjavaCallAdapterFactory后&#xff0c;Rxjava通过策略模式选择对应的adapter
关于策略模式的讲解&#xff0c;请看文章策略模式&#xff08;Strategy Pattern&#xff09;- 最易懂的设计模式解析
- 具体过程是&#xff1a;根据网络接口方法的返回值类型来选择具体要用哪种CallAdapterFactory&#xff0c;然后创建具体的CallAdapter实例
采用工厂模式使得各功能模块高度解耦
- 上面提到了两种工厂&#xff1a;CallAdapter.Factory & Converter.Factory分别负责提供不同的功能模块
- 工厂负责如何提供、提供何种功能模块
- Retrofit 只负责提供选择何种工厂的决策信息&#xff08;如网络接口方法的参数、返回值类型、注解等&#xff09;
这正是所谓的高内聚低耦合&#xff0c;工厂模式get。
关于工厂模式请看我写的文章&#xff1a;
简单工厂模式&#xff08;SimpleFactoryPattern&#xff09;- 最易懂的设计模式解析
工厂方法模式&#xff08;Factory Method&#xff09;- 最易懂的设计模式解析
抽象工厂模式&#xff08;Abstract Factory&#xff09;- 最易懂的设计模式解析
终于配置完网络请求参数&#xff08;即配置好ServiceMethod
对象&#xff09;。接下来将讲解第二行代码&#xff1a;okHttpCall对象
的创建
第二行&#xff1a;OkHttpCall okHttpCall &#61; new OkHttpCall<>(serviceMethod, args);
根据第一步配置好的ServiceMethod
对象和输入的请求参数创建okHttpCall
对象
<--OkHttpCall类 -->
public class OkHttpCall {private final ServiceMethod serviceMethod; private final Object[] args; private okhttp3.Call rawCall; private Throwable creationFailure; private boolean executed; private volatile boolean canceled; <--OkHttpCall构造函数 -->public OkHttpCall(ServiceMethod serviceMethod, Object[] args) { this.serviceMethod &#61; serviceMethod; this.args &#61; args;
}
第三行&#xff1a;return serviceMethod.callAdapter.adapt(okHttpCall);
将第二步创建的OkHttpCall
对象传给第一步创建的serviceMethod
对象中对应的网络请求适配器工厂的adapt&#xff08;&#xff09;
返回对象类型&#xff1a;Android默认的是Call<>
&#xff1b;若设置了RxJavaCallAdapterFactory&#xff0c;返回的则是Observable<>
<-- adapt&#xff08;&#xff09;详解-->
public Call adapt(Call call) {return new ExecutorCallbackCall<>(callbackExecutor, call); }ExecutorCallbackCall(Executor callbackExecutor, Call delegate) {this.delegate &#61; delegate; this.callbackExecutor &#61; callbackExecutor;}
- 采用了装饰模式&#xff1a;ExecutorCallbackCall &#61; 装饰者&#xff0c;而里面真正去执行网络请求的还是OkHttpCall
- 使用装饰模式的原因&#xff1a;希望在OkHttpCall发送请求时做一些额外操作。这里的额外操作是线程转换&#xff0c;即将子线程切换到主线程
- OkHttpCall的enqueue()是进行网络异步请求的&#xff1a;当你调用OkHttpCall.enqueue&#xff08;&#xff09;时&#xff0c;回调的callback是在子线程中&#xff0c;需要通过Handler转换到主线程进行回调。ExecutorCallbackCall就是用于线程回调&#xff1b;
- 当然以上是原生Retrofit使用的切换线程方式。如果你用Rxjava&#xff0c;那就不会用到这个ExecutorCallbackCall而是RxJava的Call&#xff0c;此处不过多展开
步骤4讲解&#xff1a;Call call &#61; NetService.getCall();
NetService
对象实际上是动态代理对象Proxy.newProxyInstance&#xff08;&#xff09;
&#xff08;步骤3中已说明&#xff09;&#xff0c;并不是真正的网络请求接口创建的对象- 当
NetService
对象调用getCall&#xff08;&#xff09;
时会被动态代理对象Proxy.newProxyInstance&#xff08;&#xff09;
拦截&#xff0c;然后调用自身的InvocationHandler # invoke&#xff08;&#xff09;
invoke(Object proxy, Method method, Object... args)
会传入3个参数&#xff1a;Object proxy:
&#xff08;代理对象&#xff09;、
Method method
&#xff08;调用的getCall()
&#xff09;
Object... args
&#xff08;方法的参数&#xff0c;即getCall&#xff08;*&#xff09;
中的*&#xff09;- 接下来利用Java反射获取到
getCall&#xff08;&#xff09;
的注解信息&#xff0c;配合args参数创建ServiceMethod对象
。
如上面步骤3描述&#xff0c;此处不再次讲解
最终创建并返回一个OkHttpCall
类型的Call对象 1. OkHttpCall
类是OkHttp
的包装类 2. 创建了OkHttpCall
类型的Call对象还不能发送网络请求&#xff0c;需要创建Request
对象才能发送网络请求总结
Retrofit采用了 外观模式 统一调用创建网络请求接口实例和网络请求参数配置的方法&#xff0c;具体细节是&#xff1a;
- 动态创建网络请求接口的实例&#xff08;代理模式 - 动态代理&#xff09;
- 创建
serviceMethod
对象&#xff08;建造者模式 & 单例模式&#xff08;缓存机制&#xff09;&#xff09; - 对
serviceMethod
对象进行网络请求参数配置&#xff1a;通过解析网络请求接口方法的参数、返回值和注解类型&#xff0c;从Retrofit对象中获取对应的网络请求的url地址、网络请求执行器、网络请求适配器 & 数据转换器。&#xff08;策略模式&#xff09; - 对
serviceMethod
对象加入线程切换的操作&#xff0c;便于接收数据后通过Handler从子线程切换到主线程从而对返回数据结果进行处理&#xff08;装饰模式&#xff09; - 最终创建并返回一个
OkHttpCall
类型的网络请求对象
3. 执行网络请求Retrofit
默认使用OkHttp
&#xff0c;即OkHttpCall类
&#xff08;实现了 retrofit2.Call
接口&#xff09;
但可以自定义选择自己需要的Call类
OkHttpCall
提供了两种网络请求方式&#xff1a;
- 同步请求&#xff1a;
OkHttpCall.execute()
- 异步请求&#xff1a;
OkHttpCall.enqueue()
下面将详细介绍这两种网络请求方式。
对于OkHttpCall的enqueue&#xff08;&#xff09;、execute&#xff08;&#xff09;此处不往下分析&#xff0c;有兴趣的读者可以看OkHttp的源码3.1 同步请求OkHttpCall.execute()
3.1.1 发送请求过程
- 步骤1&#xff1a;对网络请求接口的方法中的每个参数利用对应
ParameterHandler
进行解析&#xff0c;再根据ServiceMethod
对象创建一个OkHttp
的Request
对象 - 步骤2&#xff1a;使用
OkHttp
的Request
发送网络请求&#xff1b; - 步骤3&#xff1a;对返回的数据使用之前设置的数据转换器&#xff08;GsonConverterFactory&#xff09;解析返回的数据&#xff0c;最终得到一个
Response
对象
3.1.2 具体使用
Response response &#61; call.execute();
上面简单的一行代码&#xff0c;其实包含了整个发送网络同步请求的三个步骤。
3.1.3 源码分析
&#64;Override
public Response execute() throws IOException {okhttp3.Call call;synchronized (this) {call &#61; rawCall;if (call &#61;&#61; null) {try {call &#61; rawCall &#61; createRawCall();} catch (IOException | RuntimeException e) {creationFailure &#61; e;throw e;}}}return parseResponse(call.execute());
}<-- 关注1&#xff1a;createRawCall() -->
private okhttp3.Call createRawCall() throws IOException {Request request &#61; serviceMethod.toRequest(args);okhttp3.Call call &#61; serviceMethod.callFactory.newCall(request);if (call &#61;&#61; null) {throw new NullPointerException("Call.Factory returned null.");}return call;
}<-- 关注2&#xff1a;parseResponse&#xff08;&#xff09;-->
Response parseResponse(okhttp3.Response rawResponse) throws IOException {ResponseBody rawBody &#61; rawResponse.body();rawResponse &#61; rawResponse.newBuilder().body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength())).build();int code &#61; rawResponse.code();if (code <200 || code >&#61; 300) {}if (code &#61;&#61; 204 || code &#61;&#61; 205) {return Response.success(null, rawResponse);}ExceptionCatchingRequestBody catchingBody &#61; new ExceptionCatchingRequestBody(rawBody);try {T body &#61; serviceMethod.toResponse(catchingBody);return Response.success(body, rawResponse);} catch (RuntimeException e) {... }
}
特别注意&#xff1a;