创建Retrofit实例
Retrofit
采用构造者模式来创建实例。
new Retrofit.Builder()
.client(okhttpClient)
.baseUrl(baseUrl)
.addConverterFactory(converterFactory)
.addCallAdapterFactory(callAdapterFactory)
.build();
Retrofit.Builder
Retrofit.Builder
是Retrofit
的静态类部类,它有以下属性
private final Platform platform;
private @Nullable okhttp3.Call.Factory callFactory;
private @Nullable HttpUrl baseUrl;
private final List<Converter.Factory> converterFactories = new ArrayList<>();
private final List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>();
private @Nullable Executor callbackExecutor;
private boolean validateEagerly;
platform
platform表示Retrofit当前运行的平台。它不能通过外部设置,只能由Retrofit自动识别。callFactory
callFactory表示网络请求器的工厂,主要作用是生成网络的请求器Call
,一般情况下我们通过Builder#client()
方法设置为OkHttpClient
,当然,我们也可以通过Builder#callFactory()
设置自定义工厂。baseUrl
baseUrl是我们网络请求中的基础Url,列如域名,一般情况下都是调用Builder#baseUrl(String)
设置一个字符串,Retrofit
会调用Retrofit#baseUrl(HttpUrl)
方法自动转换成HttpUrl
类型。converterFactories
数据转换器列表,将请求到的数据转换成我们指定的类型。callAdapterFactories
请求适配器列表,默认情况下我们得到的返回结果是Call<R>
类型,通过自定义请求适配器,我们可以将结果转化为我们需要的类型,比如配合RxJava
得到Observable<R>
。callbackExecutor
回调执行器,用于Call#enqueue()
方法中,可实现线程切换,如果不指定,就会获取platform
的defaultCallbackExecutor
。validateEagerly
是否提前对接口中的方法进行验证,如果Service声明的方法非常多,提前集中验证虽然能在早期就发现错误的方法,但是可能造成明显的性能损耗,所以一般在测试阶段设置为true保证即使发现问题,在正式环境中设置为false,这样接口中的方法就会分散验证,保证了性能问题。
创建Retrofit.Builder实例
Builder(Platform platform) {
}
public Builder() {
this(Platform.get());
}
Builder(Retrofit retrofit) {
}
Retrofit.Builder
提供了三个构造函数,但是暴露给外部调用的就只有无参构造函数,调用的时候会自动获取当前平台类型,然后调用Builder(Platform platform)
方法进行初始化,同时Retrofit
也提供了快速复制一个现有的Retrofit.Builder
的方法。
public Builder newBuilder() {
return new Builder(this);
}
通过调用Retrofit#newBuilder()方法,内部就会调用Builder(Retrofit retrofit)构造函数,从而快速创建一个Builder,具体复制逻辑如下
Builder(Retrofit retrofit) {
//1
platform = Platform.get();
callFactory = retrofit.callFactory;
baseUrl = retrofit.baseUrl;
//2
for (int i = 1,
size = retrofit.converterFactories.size() - platform.defaultConverterFactoriesSize();
i < size;
i++) {
converterFactories.add(retrofit.converterFactories.get(i));
}
//3
for (int i = 0,
size =
retrofit.callAdapterFactories.size() - platform.defaultCallAdapterFactoriesSize();
i < size;
i++) {
callAdapterFactories.add(retrofit.callAdapterFactories.get(i));
}
callbackExecutor = retrofit.callbackExecutor;
validateEagerly = retrofit.validateEagerly;
}
- 可以看到即使是从一个现有的Retrofit快速创建一个Builder,platform属性也是由Retrofit自动识别,然后初始化。
- Retrofit在创建的时候会自动添加platform.defaultConverterFactories和BuiltIntConverters,所以这里复制的时候converterFactories就不需要再添加这两个了。
- 对于callAdapterFactories的添加和converterFactories类似。
设置baseUrl
public Builder baseUrl(URL baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl.toString()));
}
public Builder baseUrl(String baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
return baseUrl(HttpUrl.get(baseUrl));
}
public Builder baseUrl(HttpUrl baseUrl) {
Objects.requireNonNull(baseUrl, "baseUrl == null");
List<String> pathSegments = baseUrl.pathSegments();
if (!"".equals(pathSegments.get(pathSegments.size() - 1))) {
throw new IllegalArgumentException("baseUrl must end in /: " + baseUrl);
}
this.baseUrl = baseUrl;
return this;
}
设置baseUrl有3个重载方法,无论调用那个都需要满足下面两点
- baseUrl不能为null。
- baseUrl必须以“/”结尾。
生成Retrofit实例
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
List<Converter.Factory> converterFactories =
new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory,baseUrl,unmodifiableList(converterFactories),unmodifiableList(callAdapterFactories),callbackExecutor,validateEagerly);
}
build()方法主要执行了以下操作
- 检查baseUrl,如果为null直接抛出异常。
- 检查网络请求器工厂callFactory,如果没有设置就默认使用OkHttpClient对象。
- 检查回调执行器callbackExecutor,如果没有设置就默认使用当前platform提供的默认执行器,对于Android平台来说,使用的是MainThreadExecutor
- 添加请求适配器,包括平台提供的和用户自定义的。
- 添加数据转换器,包括BuiltInConverters和平台提供的以及用户自定义的。
- 将converterFactories和callAdapterFactories转换成只读的List,然后创建Retrofit。
创建API接口实例
有了Retrofit实例之后,调用其create()方法获取API接口实例,在此之前,我们先准备一个GitHubService
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
}
然后调用create()方法
GitHubService service = retrofit.create(GitHubService.class);
Retrofit.create()
create()方法实现比较简单,主要是使用动态代理生成传进来的API接口的实例。
public <T> T create(final Class<T> service) {
validateServiceInterface(service);
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[]{service},
new InvocationHandler() {
//省略invoke()实现
});
}
这里主要做了2件事。
- 验证APIService
- 利用动态代理生成APIService实例。
验证APIService
接口验证
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
throw new IllegalArgumentException(//......省略异常);
}
Collections.addAll(check, candidate.getInterfaces());
}
if (validateEagerly) {
//......省略方法验证
}
}
validateServiceInterface从以下方面进行检测
- APIService只能是一个接口类型。
- APIService以及其继承的接口不能包含泛型参数。
- 如果设置validateEagerly为true,就会立即对APIService中的方法进行检测,提前检测虽然能及时发现异常方法,但是会造成性能损耗。
方法验证
private void validateServiceInterface(Class<?> service) {
//......省略接口验证
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
可以看到,提前验证会跳过default方法和static修饰的方法。对于其他方***调用loadServiceMethod()进行加载。
加载方法
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null)
return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
加载ServiceMethod是一个耗时的过程,所以这里使用了缓存,对于加载过的方***缓存到serviceMethodCache中,serviceMethodCache定义如下:
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ConcurrentHashMap是线程安全的,如果serviceMethodCache中有当前method则直接取出返回,否则调用ServiceMethod.parseAnnotations()创建一个ServiceMethod,然后放入serviceMethodCache并返回结果。
ServiceMethod的parseAnnotations方***创建ServiceMethod,这里只暂时只关注主流程,就不深入查看。
Method.invoke()
public <T> T create(final Class<T> service) {
//......省略其他代码
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args)throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
}
首先,如果当前方法method来源于Object,则正常调用,对于其他方法,如果是default方法则交由平台platform的invokeDefaultMethod()方法执行,否则将method转换成ServiceMethod然后执行。
执行请求
经过前面我们获取到了APIService的实例,然后通过它就可以调用具体方法,然后执行请求
Call<List<Repo>> repos = service.listRepos("user").execute();
请求的执行有同步和异步两种,这里以同步为例
//OkHttpCall.java
public Response<T> execute() throws IOException {
okhttp3.Call call;
synchronized (this) {
if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = getRawCall();
}
if (canceled) {
call.cancel();
}
return parseResponse(call.execute());
}
可以看到Retrofit最后其实是调用来的OkHttp的Call执行了请求,它主要做了以下操作
- 判断请求是否执行过,如果执行过了就抛出异常。
- 通过getRawCall()方法将retrofit2.Call转换成okhttp3.Call。
- 通过okhttp3.Call执行请求。
- 上一步执行请求返回的结果是okhttp3.Response,通过parseResponse()将okhttp3.Response转化为retrofit2.Response。
到这里Retrofit使用的主流程分析完了,对于Call和Response转换等源码将在后面进行分析。