文章目录
- 一、简介
- 二、请求流程
- 三、创建Retrofit实例
- 四、创建网络请求接口的实例
- 五、执行网络请求
一、简介
Retrofit基于OkHttp通过注解配置网络请求参数。支持同步、异步的网络请求,支持Gson、Json、XML、Protobuf等多种数据的解析、序列化。
Retrofit有以下优点:
- 功能强大
支持同步、异步网络请求、支持Rxjava、支持多种数据解析 - 简单
由注解配置网络请求参数,并运用了大量的设计模式 - 拓展性强
高度封装功能模块,可自定义Converter等来高解耦
二、请求流程
具体过程如下:
- ① 解析网络请求接口的注解、配置网络请求参数
- ② 通过动态代理生成网络请求对象
- ③ 网络请求适配器将网络请求对象进行平台适配(Android、RxJava、Guava、Java8)
- ④ 网络请求执行器发送网络请求
- ⑤ 数据转换器 解析服务器返回的数据
- ⑥ 回调执行器切换线程
- ⑦ 用户在主线程处理返回结果
三、创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://www.baidu.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Retrofit实例是使用 建造者模式 通过Builder类构建出来的,将复杂对象的构建、表示进行分离,用户可以在不知道对象创建细节情况下就可以直接创建复杂对象。
3.1 new Retrofit
这里配置了一堆的成员变量:
- serviceMethod:包含所有网络请求的对象—> private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
- baseUrl:网络请求url
- callFactory:网络请求工厂—>生成Call
- adapterFactories:网络请求适配器工厂的集合—>生成CallAdapter
- converterFactories:数据转换器工厂的集合—>生产Converter
- callbackExecutor:回调方法执行器
- validateEagerly:标志位,是否提前对接口的注解进行验证转换
这里的一些xxxFactory用到了工厂模式!将 类实例化的操作 与 使用对象的操作 分开,使得使用者不用知道具体参数就可以实例化出所需要的“产品”类。
public final class Retrofit {
//网络请求配置对象(对网络请求接口中的方法注解进行解析后得到的对象)
//存储网络请求相关配置(网络请求方法、数据转换器、网络请求适配器、网络请求工厂、基地址)
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
//网络请求器的工厂,生成网络请求器Call,Retrofit默认使用OkHttp
private final okhttp3.Call.Factory callFactory;
//网络请求url
private final HttpUrl baseUrl;
//数据转换器工厂的集合,用来生产数据转换器converter
private final List<Converter.Factory> converterFactories;
//网络请求适配器工厂的集合,用来生成网络请求适配器CallAdapter
private final List<CallAdapter.Factory> adapterFactories;
//回调方法执行器
private final Executor callbackExecutor;
//是否提前对业务接口中的注解进行验证转换的标志位
private final boolean validateEagerly;
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> adapterFactories,
Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
//unmodifiableList(list)相当于UnmodifiableList<E>(list),
//创建的新对象能够对list数据进行访问,但是不能对list集合中的元素进行修改
this.converterFactories = unmodifiableList(converterFactories); // Defensive copy at call site.
this.adapterFactories = unmodifiableList(adapterFactories); // Defensive copy at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
省略......
}
callAdapterFactory负责生产callAdapter,即网络请求适配器,网络请求执行器Call(默认OkHttpCall)的适配器。有以下4种:
- ExecutorCallAdapterFactory 默认
- GuavaCallAdapterFactory
- Java8CallAdapterFactory
- RxJavaCallAdapterFactory
CallAdapter的作用:将默认的Call(即OkHttpCall)转换,以适应不同平台。
默认使用OkHttpCall通过ExecutorCallbackCall切换线程,但RxJava用来切换线程不需要Handler,更方便。用RxJavaCallAdapterFactoryCallAdapter来将OkHttpCall转换为RxJava:
// 把response封装成rxjava的Observeble,然后进行流式操作
Retrofit.Builder.addCallAdapterFactory(newRxJavaCallAdapterFactory().create());
3.2 xx.Builder()
Builder类的构建用到了建造者模式!先看看Builder类,Builder类的成员变量和Retrofit类的成员变量是对应的,所以Retrofit类的成员变量基本上都是通过Builder类来配置的。
<-- Builder类-->
public static final class Builder {
private Platform platform;
private okhttp3.Call.Factory callFactory;
private HttpUrl baseUrl;
private List<Converter.Factory> converterFactories = new ArrayList<>();
private List<CallAdapter.Factory> adapterFactories = new ArrayList<>();
private Executor callbackExecutor;
private boolean validateEagerly;
<-- 步骤1 -->
// Builder的构造方法(无参)
public Builder() {
this(Platform.get());
}
...
}
<-- 步骤2 -->
class Platform {
private static final Platform PLATFORM = findPlatform();
// 将findPlatform()赋给静态变量
static Platform get() {
return PLATFORM;
// 返回静态变量PLATFORM,即findPlatform() ->>步骤3
}
<-- 步骤3 -->
private static Platform findPlatform() {
try {
Class.forName("android.os.Build");
// Class.forName(xxx.xx.xx)的作用:要求JVM查找并加载指定的类(即JVM会执行该类的静态代码段)
if (Build.VERSION.SDK_INT != 0) {
return new Android();
// 此处表示:如果是Android平台,就创建并返回一个Android对象 ->>步骤4
}
} catch (ClassNotFoundException ignored) {
}
try {
// 支持Java平台
Class.forName("java.util.Optional");
return new Java8();
} catch (ClassNotFoundException ignored) {
}
try {
// 支持iOS平台
Class.forName("org.robovm.apple.foundation.NSObject");
return new IOS();
} catch (ClassNotFoundException ignored) {
}
// 说明Builder指定了运行平台为Android
return new Platform();
}
...
}
<-- 步骤4 -->
// 用于接收服务器返回数据后进行线程切换在主线程显示结果
static class Android extends Platform {
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
// 创建默认的网络请求适配器工厂
return new ExecutorCallAdapterFactory(callbackExecutor);
}
@Override
public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 作用:将子线程切换到主线程,并在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
static class MainThreadExecutor implements Executor {
// 获取与Android 主线程绑定的Handler
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
// 该Handler是上面获取的与Android 主线程绑定的Handler
// 在UI线程进行对网络请求返回数据处理等操作。
handler.post(r);
}
}
}
// 下面继续看步骤5的Builder有参构造方法
<-- 步骤5 -->
// Builder类的构造函数2(有参)
public Builder(Platform platform) {
// 接收Platform对象(Android平台)
this.platform = platform;
// 通过传入BuiltInConverters()对象配置数据转换器工厂(converterFactories)
// converterFactories是一个存放数据转换器Converter.Factory的数组
// 配置converterFactories即配置里面的数据转换器
converterFactories.add(new BuiltInConverters());
// BuiltInConverters是一个内置的数据转换器工厂(继承Converter.Factory类)
// new BuiltInConverters()是为了初始化数据转换器
}
5步走:
- ①用this调用自己的有参构造方法public Builder(Platform platform),并调用Platform.get()方法传入platform对象
- ②return findPlatform()
- ③Retrofit2.0支持Android、Ios、Java3个平台,最后 将一个指定的平台对象platform return给Builder的有参构造方法public Builder(Platform platform)
- ④接收服务器返回的数据后,从子线程切换到主线程显示:构建默认的网络请求适配器工厂ExecutorCallAdapterFactory,生产的adpater会使得Call在异步调用时在指定的Executor上执行回调(用到了策略模式)。获取到与主线程绑定的Handler,通过handler.post()方法在UI线程显示数据。切换线程的流程:回调ExecutorCallAdapterFactory生成一个ExecutorCallbackCall对象,通过调用ExecutorCallbackCall.enqueue(CallBack)方法调用MainThreadExecutor的execute()方法,通过handler切换到主线程
- ⑤Builder类的有参构造方法会接收Platform对象(Android平台),并且会配置数据转换器工厂converterFactories
对Builder类,它设置了默认的Platform-Android、网络请求适配器工厂CallAdapterFactory(CallAdapter会对原始Call再次封装,如Call —>Observable)、数据转换器工厂converterFactory、回调执行器callbackExecutor。这里仅设置了默认值,并未真正配置到具体Retrofit类的成员变量中。
3.3 .baseUrl(“http://www.baidu.com/”)
配置Retrofit类的网络请求url,将传入的String类型的url转化为适应OkHttp类型的HttpUrl,并通过一系列判断来检查是否“合格”。
通过HttpUrl.parse(baseUrl)将url类型转换,并进一步加工(将HttpUrl分割为几个路径碎片,检查最后一个碎片是否以“/”结尾。否则,就抛出异常)
<-- 步骤1 -->
public Builder baseUrl(String baseUrl) {
// 检查baseUrl不为空
checkNotNull(baseUrl, "baseUrl == null");
//把String类型的url转化为适应OkHttp的HttpUrl类型
HttpUrl httpUrl = HttpUrl.parse(baseUrl);
if (httpUrl == null) {
throw new IllegalArgumentException("Illegal URL: " + baseUrl);
}
//返回带HttpUrl类型参数的baseUrl
return baseUrl(httpUrl);
}
<-- 步骤2 -->
public Builder baseUrl(HttpUrl baseUrl) {
//还得检查不为null
checkNotNull(baseUrl, "baseUrl == null");
//把baseUrl参数分割成几个路径碎片
List<String> pathSegments = baseUrl.pathSegments();
//检查最后一个碎片,判断baseUrl是不是以“/”结尾。否则就抛异常
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
3.4 .addConverterFactory(GsonConverterFactory.create())
这里主要做了两件事:
- 1 内部的GsonConverterFactory.create()会调用create(new Gson)方法来创建一个含有Gson对象的GsonConverterFactory
- 2 讲这个含有Gson实例的GsonConverterFactory,通过addConverterFactory方法,放到数据转化器 工厂converterFactories中
public final class GsonConverterFactory extends Converter.Factory {
<-- 步骤1 -->
public static GsonConverterFactory create() {
//创建一个Gson对象--->步骤2
return create(new Gson());
}
<-- 步骤2 -->
public static GsonConverterFactory create(Gson gson) {
//创建一个含有Gson对象实例的GsonConverterFactory--->步骤3
return new GsonConverterFactory(gson);
}
private final Gson gson;
<-- 步骤3 -->
private GsonConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
省略......
}
// 将刚刚创建的GsonConverterFactory放到converterFactories数组中
//这里需要联系3.2章节的步骤5,添加了一个内置数据转换器工厂BuiltInConverters()后又放入了一个GsonConverterFactory
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(checkNotNull(factory, "factory == null"));
return this;
}
由此可以看出:Retrofit默认Gson解析,也可以继承Converter.Factory自定义,来解析其他格式数据(Json、XML、Protocobuf)
3.5 .build()
通过前面步骤设置的遍变量,配置好Retrofit类的所有成员变量,进而成功创建Retrofit实例。
配置:
- 1 网络请求执行器, okhttp3.Call.Factory callFactory = this.callFactory;若未指定,就new OkHttpClient()使用OkHttp
- 2 回调方法执行器callbackExecutor。若未指定,就默认使用Platform对应的callbackExecutor
- 3 网络请求适配器工厂,List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
- 4 数据转换器工厂,List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
最后,这个“武装到牙齿”的Rertrofit就配置好了,return
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
// 配置网络请求执行器-CallFactory
okhttp3.Call.Factory callFactory = this.callFactory;
// 如果没指定,默认使用OkHttp,所以Retrofit默认使用OkHttp进行网络请求
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 配置回调方法执行器-callbackExecutor
Executor callbackExecutor = this.callbackExecutor;
// 如果没指定,默认使用Platform检测环境时默认的callbackExecutor
//即Android默认的callbackExecutor
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// 配置网络请求适配器工厂-CallAdapterFactory
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
// 将3.2章节步骤4中创建的CallAdapter.Factory请求适配器 添加到集合器末尾
//请求适配器工厂集合存储顺序为:自定义1适配器工厂、自定义2适配器工厂...默认适配器工厂ExecutorCallAdapterFactory
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// 配置数据转换器工厂-converterFactory
// 在3.2章节-步骤2中已经添加了内置的数据转换器BuiltInConverters()到集合器首位,
// 在3.2章节-步骤4中又插入了一个Gson的转换器GsonConverterFactory到集合器第二位
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
// 数据转换器工厂集合的存储顺序:默认的数据转换器工厂BuiltInConverters、自定义1数据转换器工厂GsonConverterFactory、自定义2数据转换器工厂...
// 最后return一个Retrofit对象,并传入以上配置好的成员变量
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
至此,Retrofit就使用建造者模式,通过Builder类创建了一个Retrofit实例。具体配置了:
- Platform - Android
- baseUrl
- callFactory - OkHttpCall
- adapterFactories - ExecutorCallAdapterFactory
- converterFactories
- callbackExecutor
得益于建造者模式,并不需要关心配置细节就可以创建好Retrofit实例!
四、创建网络请求接口的实例
<-- 步骤1:定义接收网络数据的类 -->
public class JavaBean {
...
}
<-- 步骤2:定义网络请求的接口类 -->
public interface Api {
@GET(...)
Call<JavaBean> getCall();
}
<-- 步骤3:在MainActivity创建接口类实例 -->
API api= retrofit.create(AccessApi.class);
<-- 步骤4:对发送请求的url进行封装,即生成最终的网络请求对象 -->
Call<JavaBean> call = api.getCall();
4.1 创建接口类实例:API api= retrofit.create(AccessApi.class);
采用外观模式访问,内部使用代理模式。选用外观模式:可在内部调用各个方法来创建网络请求接口的实例,配置网络请求参数。有效的降低系统耦合度;选用动态代理:代理类在运行时由程序动态生成,return (T) Proxy.newProxyInstance(…InvocationHandler…)动态生成网络请求接口的代理类,并将代理类的实例创建,交给InvocationHandler作为具体实现,最终返回一个动态代理对象。生成实例的过程中含有生成实现类的缓存机制,运用了单例模式:result = serviceMethodCache.get(method)
好处:
- ①当api.getCall()时,会进行拦截。所有的调用都会集中转发到InvocationHandler#invoke()中,几种处理
- ②可获取网络请求接口实例上的所有注解
- ③更方便的封装ServiceMethod
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
//判断是否需要提前验证
if (validateEagerly) {
//对接口中每个方法的注解进行解析,并得到一个ServiceMethod对象,
//以Method为key将该对象存入LinkedHashMap集合中。
eagerlyValidateMethods(service);
}
//如果不提前验证,就动态解析对应方法,得到一个ServiceMethod对象,最后存到LinkedHashMap中,类似延迟加载
//创建网络请求接口的动态代理对象,通过动态代理来创建网络请求接口的实例并返回。
//该动态代理是为了拿到网络请求接口上的所有注解
return (T) Proxy.newProxyInstance(
service.getClassLoader(), // 动态生成接口的实现类
new Class<?>[] { service }, // 动态创建实例
new InvocationHandler() { //将代理类的实现交给InvocationHandler类作为具体的实现
private final Platform platform = Platform.get();
//在InvocationHandler类的invoke()实现中,除了执行真正的逻辑(如再次转发给真正的实现类对象),
//还会进行统计执行时间、初始化和清理、检查接口调用等其他操作
@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);
}
//这才是最关键的!
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
private void eagerlyValidateMethods(Class<?> service) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
// 将传入的serviceMethod对象加入到LinkedHashMap<Method,ServiceMethod>集合中,
// LinkedHashMap好处: lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,提供了一种Lru算法的实现
if (!platform.isDefaultMethod(method)) {
loadServiceMethod(method);
}
}
}
以上主要做了两件事:
- 1 通过validateEagerly判断是否提前验证。若需要,则调用eagerlyValidateMethods方法解析接口中每个方法的注解,得到一个ServiceMethod对象。将其以method为key存储到LinkedHashMap中:LinkedHashMap<Method, ServiceMethod>。使用LinkedHashMap的好处是lruEntries.values().iterator().next()获取到的是集合最不经常用到的元素,LRU的体现。若不提前验证,就对方法动态解析,得到ServiceMethod对象,放到LinkedHashMap中
- 2 创建爱你网络请求接口的动态代理对象,即动态代理创建网络请求接口实例。动态代理的目的是拿到接口实例上的所有注解,其中主要将代理类的实现交给InvocationHandler#invoke()
关于InvocationHandler#invoke(),主要做了3件事!
4.1.1 ServiceMethod serviceMethod = loadServiceMethod(method);
目的就是读取网络请求接口中的方法,并根据配置好的属性来配置serviceMethod对象。这个loadServiceMethod方法就是负责加载serviceMethod对象,以便和网络请求接口中定义的方法一一对应。
这里的ServiceMethod对象的创建用到了缓存机制:利用单例模式实现一个ServiceMethod对象对应 网络请求接口 中的一个方法。每次获取接口实例都是传入class对象,而class对象在进程内是单例的,因此获取它的同一个Method对象也是单例的。
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
// 设置线程同步锁
synchronized (serviceMethodCache) {
// ServiceMethod对象采用单例模式创建,在创建ServiceMethod对象前,
// 先看 serviceMethodCache 有没有缓存之前创建过的网络请求实例
result = serviceMethodCache.get(method);
// serviceMethodCache 没缓存就利用建造者模式构建
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
ServiceMethod的加载分为以下3步:
① 设置线程同步锁synchronized (serviceMethodCache)
②单例模式创建ServiceMethod对象,即先看看ServiceMethodCache是否缓存过创建好的网络请求实例
③如果serviceMethodCache没有缓存,就利用建造者模式构建ServiceMethod实例:result = new ServiceMethod.Builder(this, method).build();
4.1.1.1 建造者模式创建ServiceMethod1~构造函数
ServiceMethod的构造,传入各种网络请求参数。如:网络请求工厂、网络请求适配器工厂、Response数据转换器、网络请求(相对)地址、http方法、http请求头、http报文body的类型、方法参数处理器parameterHandler(用来解析定义的方法的参数,并在构造Http请求时设置参数)
<-- ServiceMethod 类 -->
public final class ServiceMethod {
final okhttp3.Call.Factory callFactory; // 网络请求工厂
final CallAdapter<?> callAdapter; // 网络请求适配器工厂
//作用:负责把服务器返回的数据(JSON或者其他格式,由 ResponseBody 封装)转化为 T 类型的对象;
private final Converter<ResponseBody, T> responseConverter; // Response内容转换器
private final HttpUrl baseUrl; // 网络请求地址
private final String relativeUrl; // 网络请求的相对地址
private final String httpMethod; // 网络请求的Http方法
private final Headers headers; // 网络请求的http请求头 键值对
private final MediaType contentType; // 网络请求的http报文body的类型
// 方法参数处理器,作用:负责解析 API 定义时每个方法的参数,并在构造 HTTP 请求时设置参数;
private final ParameterHandler<?>[] parameterHandlers;
<-- ServiceMethod 类的构造函数 -->
ServiceMethod(Builder<T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.responseConverter = builder.responseConverter;
this.baseUrl = builder.retrofit.baseUrl();
this.relativeUrl = builder.relativeUrl;
this.httpMethod = builder.httpMethod;
this.headers = builder.headers;
this.contentType = builder.contentType; .
this.hasBody = builder.hasBody; y
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
4.1.1.2 建造者模式创建ServiceMethod2~.Builder(this, method)
获取网络请求接口方法中的注释、参数类型、注解内容等
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
//获取网络请求接口方法中的注释
this.methodAnnotations = method.getAnnotations();
//获取网络请求接口方法中的参数类型
this.parameterTypes = method.getGenericParameterTypes();
//获取网络IQ那个IQu借款发放中的注解内容
this.parameterAnnotationsArray = method.getParameterAnnotations();
}
4.1.1.3 建造者模式创建ServiceMethod3~.build()
build()方法是控制ServiceMethod对象的生成流程:
- ①根据网络请求接口方法中的返回值和注解类型,依次从Retrofit对象中获取对应的网络请求适配器(createCallAdapter()方法)及返回的数据类型(callAdapter.responseType()方法)、对应的数据转换器。遍历Converter.Factory集合取出合适的工厂做数据转换(这里指的Gson)
- ②根据方法的注解,为ServiceMethod域赋值
- ③对每个方法的所有参数的注解进行解析,获得ParameterHandler对象。该对象保存有一个Request内容转换器
这里涉及到了策略模式:选择RxJavaCallAdapterFactory后,即可通过策略模式得到对应的adapter。只需要根据网络请求接口方法的返回值类型,就能选择使用哪种CallAdapterFactory,然后创建具体的CallAdapter实例。
至此,就配置好了网络请求参数,即ServiceMethod对象。
public ServiceMethod build() {
// 关注点1
//根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
callAdapter = createCallAdapter();
//根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取该网络请求适配器返回的数据类型
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?");
}
// 关注点3
//根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取对应的数据转换器
responseConverter = createResponseConverter();
//解析网络请求接口方法中的注解,从而获取Http请求的方法。
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
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).");
}
}
//获取当前方法的参数数量
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.");
}
//对方法参数中的注解进行解析(Body、Query等),从而获取到一个ParameterHandler<?>对象
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);
}
<-- 关注点1:createCallAdapter() -->
private CallAdapter<?> createCallAdapter() {
//获取网络请求接口方法里的返回值类型
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError("Service methods cannot return void.");
}
//获取网络请求接口方法中的注解,此处为@GET
Annotation[] annotations = method.getAnnotations();
try {
//关注点2
//根据网络请求接口方法中的返回值和注解类型,从Retrofit对象中获取对应的网络请求适配器
return retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(e, "Unable to create call adapter for %s", returnType);
}
}
<-- 关注点2:retrofit.callAdapter() -->
public CallAdapter<?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?> nextCallAdapter(CallAdapter.Factory skipPast, Type returnType,
Annotation[] annotations) {
// 遍历 CallAdapter.Factory 集合寻找合适的工厂(该工厂集合在第一步构造 Retrofit 对象时进行添加)
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:createResponseConverter() -->
private Converter<ResponseBody, T> createResponseConverter() {
Annotation[] annotations = method.getAnnotations();
try {
// responseConverter 还是由 Retrofit 类提供 -->关注点4
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) {
throw methodError(e, "Unable to create converter for %s", responseType);
}
}
<-- 关注点4:responseBodyConverter() -->
public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
return nextResponseBodyConverter(null, type, annotations);
}
public <T> Converter<ResponseBody, T> nextResponseBodyConverter(Converter.Factory skipPast,
int start = converterFactories.indexOf(skipPast) + 1;
for (int i = start, count = converterFactories.size(); i < count; i++) {
// 关注点5 获取Converter 过程
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this);
// 遍历 Converter.Factory 集合并寻找合适的工厂(该工厂集合在构造 Retrofit 对象时进行添加)
// 由于构造Retroifit默认Gson解析方式,所以取出的是GsonResponseBodyConverter
// Retrofit - Converters 还提供了 JSON,XML,ProtoBuf 等类型数据的转换功能。
}
<-- 关注点5:responseBodyConverter() -->
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
// 根据目标类型,利用 Gson#getAdapter 获取相应的 adapter
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonResponseBodyConverter<>(gson, adapter);
}
// 做数据转换时调用 Gson 的 API 即可。
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
JsonReader jsonReader = gson.newJsonReader(value.charStream());
try {
return adapter.read(jsonReader);
} finally {
value.close();
}
}
}
4.1.2 OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
根据刚才配置好的ServiceMethod对象和输入的参数args,创建OkHttpCall对象
<--OkHttpCall类 -->
public class OkHttpCall {
// 含有所有网络请求参数信息的对象
private final ServiceMethod<T> serviceMethod;
// 网络请求接口的参数
private final Object[] args;
//实际进行网络访问的类
private okhttp3.Call rawCall;
//几个状态标志位
private Throwable creationFailure;
private boolean executed;
private volatile boolean canceled;
<--OkHttpCall构造函数 -->
public OkHttpCall(ServiceMethod<T> serviceMethod, Object[] args) {
// 传入了配置好的ServiceMethod对象和输入的请求参数
this.serviceMethod = serviceMethod;
this.args = args;
}
4.1.3 return serviceMethod.callAdapter.adapt(okHttpCall);
将上一步创建的OkHttpCall对象传递给ServiceMethod对象中对应的网络请求适配器工厂的adap()方法中,返回的对象类型是默认的Call<>。如果设置了RxJavaCallAdapterFactory,就返回Observable<>
参数齐全的OkHttpCall对象最终交给了静态代理delegate,静态代理作用:代理执行被代理者的方法,且可在要执行的方法前后加入自己的动作,进行对系统功能的拓展
public <R> Call<R> adapt(Call<R> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
// 把参数齐全的OkhttpCall对象交给静态代理delegate
this.delegate = delegate;
// 传入上面定义的回调方法执行器,用于进行线程切换
this.callbackExecutor = callbackExecutor;
}
传入定义的回调方法执行器callbackExecutor,用于线程切换。OkHttpCall.enqueue()用于异步请求,回调的callback在子线程,需要Handler切换到UI线程进行回调。ExecutorCallbackCall就是用于线程回调的。
ExecutorCallbackCall就是装饰者,这里用到了装饰模式,真正的执行网络请求的还是OkHttpCall。这样做的原因就是希望OkHttpCall在发请求时,还能额外的做线程切换。
4.2 调用接口方法:api.getCall()
api为动态代理对象Proxy.newProxyInstance(),并非真正的接口创建的对象。当调用接口方法时,会被动态代理对象Proxy.newProxyInstance()拦截,然后调用自己的InvocationHandler#invoke()方法。invoke()方法会将代理对象Object proxy、调用的方法Method传入。最后利用反射得到定义的接口方法的注解信息,配合args创建ServiceMethod对象。最终创建并返回一个OkHttpCall类型的Call对象。但是它只是OkHttp的包装类,并不能发送网络请求,必须得创建好Request对象后才行。
4.3 总结
由动态代理创建接口实例、建造者&单例模式创建ServiceMethod对象、策略模式对ServiceMethod进行网络请求参数的配置(主要体现在ConverterFactory的选用)、装饰模式对ServiceMethod加入线程切换操作。
最终返回OkHttpCall类型的网络请求对象
五、执行网络请求
5.1 OkHttpCall.execute()同步请求
同步请求流程如下:
- ①对网络请求接口的方法中的每个参数,利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象
- ②使用OkHttp的Request发送网络请求;
- ③对返回的数据使用之前设置的GsonConverterFactory解析,最终得到一个Response对象。这里还会检查状态码,将response body传入serviceMethod中,serviceMethod再通过GsonConverterFactory将response body转换为Java对象
@Override
public Response<T> execute() throws IOException {
okhttp3.Call call;
// 设置同步锁
synchronized (this) {
call = rawCall;
if (call == null) {
try {
// 步骤1:创建一个OkHttp的Request对象请求
call = rawCall = createRawCall();
} catch (IOException | RuntimeException e) {
creationFailure = e;
throw e;
}
}
}
// 步骤2:调用OkHttpCall的execute()发送网络请求(同步)
// 步骤3:解析网络请求返回的数据parseResponse()
return parseResponse(call.execute());
}
// 创建一个OkHttp的Request对象请求
private okhttp3.Call createRawCall() throws IOException {
// 从ServiceMethod的toRequest()返回一个Request对象
Request request = serviceMethod.toRequest(args);
// 根据serviceMethod和request对象创建 一个okhttp3.Request
okhttp3.Call call = serviceMethod.callFactory.newCall(request);
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
rawResponse = rawResponse.newBuilder()
.body(new NoContentResponseBody(rawBody.contentType(), rawBody.contentLength()))
.build();
// 收到返回数据后进行状态码检查
int code = rawResponse.code();
if (code < 200 || code >= 300) {
}
if (code == 204 || code == 205) {
return Response.success(null, rawResponse);
}
ExceptionCatchingRequestBody catchingBody = new ExceptionCatchingRequestBody(rawBody);
try {
// 等Http请求返回后 & 通过状态码检查后,将response body传入ServiceMethod中,
//ServiceMethod通过调用Converter接口(之前设置的GsonConverterFactory)
//将response body转成一个Java对象,即解析返回的数据
T body = serviceMethod.toResponse(catchingBody);
// 生成Response类
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
... // 异常处理
}
}
5.2 OkHttpCall.enqueue()异步请求
使用静态代理delegate.enqueue()执行异步请求:
- ①对网络请求接口的方法中的每个参数,利用对应ParameterHandler进行解析,再根据ServiceMethod对象创建一个OkHttp的Request对象,再将其封装为OkHttp.Call
- ②使用OkHttp的Request发送网络请求,delegate是OkHttpCall的静态代理,最终还是调用OkHttp.enqueue
- ③对返回的数据使用之前设置的GsonConverterFactory解析,最终得到一个Response对象。这里还会检查状态码,将response body传入serviceMethod中,serviceMethod再通过GsonConverterFactory将response body转换为Java对象
- ④线程切换到UI线程处理结果:callbackExecutor.execute(new Runnable…)通过Handler异步回调将结果传回到UI线程。
线程切换是通过一开始创建Retrofit对象时,Platform检查运行环境为Android时进行创建的,创建默认的回调执行器工厂,回调ExecutorCallAdapterFactory生成ExecutorCallbackCall对象,调用其enqueue()方法,从而调用MainThreadExecutor的execute()方法,通过Handler切换到主线程。这里线程切换用到了适配器模式
<-- call.enqueue()解析 -->
@Override
public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {
// 使用静态代理 delegate进行异步请求 ->>分析1
@Override
public void onResponse(Call<T> call, final Response<T> response) {
// 步骤4:线程切换,从而在主线程显示结果
callbackExecutor.execute(new Runnable() {
// 最后Okhttp的异步请求结果返回到callbackExecutor
// callbackExecutor.execute()通过Handler异步回调将结果传回到主线程进行处理(如显示在Activity等等),即进行了线程切换
// 具体是如何做线程切换 ->>分析2
@Override
public void run() {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
}
});
}
@Override
public void onFailure(Call<T> call, final Throwable t) {
callbackExecutor.execute(new Runnable() {
@Override public void run() {
callback.onFailure(ExecutorCallbackCall.this, t);
}
});
}
});
}
<-- 分析1:delegate.enqueue()解析 -->
@Override
public void enqueue(final Callback<T> callback) {
okhttp3.Call call;
Throwable failure;
// 步骤1:创建OkHttp的Request对象,再封装成OkHttp.call
// delegate代理在网络请求前的动作:创建OkHttp的Request对象,再封装成OkHttp.call
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure;
if (call == null && failure == null) {
try {
call = rawCall = createRawCall();
// 创建OkHttp的Request对象,再封装成OkHttp.call
// 方法同发送同步请求,此处不作过多描述
} catch (Throwable t) {
failure = creationFailure = t;
}
}
// 步骤2:发送网络请求
// delegate是OkHttpcall的静态代理
// delegate静态代理最终还是调用Okhttp.enqueue进行网络请求
call.enqueue(new okhttp3.Callback() {
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
// 步骤3:解析返回数据
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();
}
}
});
}
<-- 分析2:异步请求后的线程切换-->
// 线程切换是通过一开始创建Retrofit对象时Platform在检测到运行环境是Android时进行创建的:
// 采用适配器模式
static class Android extends Platform {
// 创建默认的回调执行器工厂
// 如果不将RxJava和Retrofit一起使用,一般都是使用该默认的CallAdapter.Factory
// 后面会对RxJava和Retrofit一起使用的情况进行分析
@Override
CallAdapter.Factory defaultCallAdapterFactory(Executor callbackExecutor) {
return new ExecutorCallAdapterFactory(callbackExecutor);
}
@Override
public Executor defaultCallbackExecutor() {
// 返回一个默认的回调方法执行器
// 该执行器负责在主线程(UI线程)中执行回调方法
return new MainThreadExecutor();
}
// 获取主线程Handler
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable r) {
// Retrofit获取了主线程的handler
// 然后在UI线程执行网络请求回调后的数据显示等操作。
handler.post(r);
}
}
}