携手创作,共同生长!这是我参与「日新计划 8 月更文应战」的第1天,点击查看活动概况
Retrofit源码系列文章:
- 挖一挖Retrofit源码(一)
- 挖一挖Retrofit源码(二)
- Retrofit之CallAdapter解析
- Retrofit之自定义CallAdapter
- Retrofit之Converter解析
简介
Retrofit是一个根据OkHttp的网络恳求框架,对OkHttp的恳求和成果进行处理,Retrofit仅负责网络恳求接口的封装并自动生成实践网络恳求的代码,而网络恳求的作业本质上是OkHttp完成的。
运用建议网络恳求后,实践上是运用 Retrofit 接口层封装恳求参数、Header、Url等信息,之后由OkHttp完成后续的恳求操作,OkHttp将服务器回来的原始数据交给Retrofit,Retrofit依据用户的需求对成果进行解析。
PS:本文根据Retrofit版本2.8.0
源码解析
1. 创立Retrofit实例
val retrofit = Retrofit.Builder()
.baseUrl("https://test.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
Retrofit实例是运用建造者形式经过Builder类创立的,并初始化一些装备项,下面将对创立Retrofit实例进行详细分析。
1.1 Retrofit类
public final class Retrofit {
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
final okhttp3.Call.Factory callFactory; //出产网络恳求器(Call)的工厂,默许运用OkHttp
final HttpUrl baseUrl; //url地址
final List<Converter.Factory> converterFactories; //数据转化器(converter)的工厂List
final List<CallAdapter.Factory> callAdapterFactories; //出产网络恳求适配器(CallAdapter)的工厂List
final @Nullable Executor callbackExecutor; //回调办法履行器
final boolean validateEagerly; //是否提早对业务接口中的注解进行验证转化的标志位
Retrofit(okhttp3.Call.Factory callFactory, HttpUrl baseUrl,
List<Converter.Factory> converterFactories, List<CallAdapter.Factory> callAdapterFactories,
@Nullable Executor callbackExecutor, boolean validateEagerly) {
this.callFactory = callFactory;
this.baseUrl = baseUrl;
this.converterFactories = converterFactories; // Copy+unmodifiable at call site.
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor;
this.validateEagerly = validateEagerly;
}
//省略其他代码
......
}
其中callFactory、converterFactories、callAdapterFactories表现了工厂形式,运用者不需要关怀详细参数就能够实例化出所需要的类。
1.2 Builder类
public static final class Builder {
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;
//①Builder的有参结构函数
Builder(Platform platform) {
this.platform = platform;
}
//②Builder的无参结构函数
public Builder() {
this(Platform.get());
}
......
}
能够看出Builder类的成员变量和Retrofit类的是对应的,所以Retrofit类的成员变量基本上是经过Builder类来装备。
代码里①接收了Platform目标并设进Builder类的Platform,而②则是用this调用了自己的有参结构函数①并经过调用Platform.get()传入Platform目标,即Builder的结构函数中检测了当前的运转渠道。
1.3 addConverterFactory办法
public Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null"));
return this;
}
前面创立Retrofit实例的时分是把GsonConverterFactory.create()传进了addConverterFactory办法,而GsonConverterFactory.create()实践上是创立并回来了一个含有Gson目标实例的GsonConverterFactory,即指定Retrofit运用Gson进行解析数据,也能够运用其他解析方式(如Json、XML或Protocobuf)或许能够运用自定义数据解析器(有必要承继Converter.Factory)。addCallAdapterFactory办法也是相似的,能够增加Retrofit内置的CallAdapterFactory,也能够运用自定义的适配器。
1.4 build办法
在创立Retrofit.Builder目标并进行自定义装备后,咱们就要调用build办法来结构出Retrofit目标了,下面来看看build()里干了什么:
public Retrofit build() {
//有必要要装备baseUrl
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
//装备网络恳求履行器,若无指定则默许运用OkHttp
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
//装备回调办法履行器,Android渠道下默许为MainThreadExecutor
//MainThreadExecutor的作用:切换线程(子->>主线程),并在主线程(UI线程)中履行回调办法
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//装备网络恳求适配器工厂,将默许适配器工厂DefaultCallAdapterFactory增加至List结尾
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
callAdapterFactories.addAll(platform.defaultCallAdapterFactories(callbackExecutor));
// Make a defensive copy of the converters.
//装备数据转化器工厂
List<Converter.Factory> converterFactories = new ArrayList<>(
1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize());
// Add the built-in converter factory first. This prevents overriding its behavior but also
// ensures correct behavior when using converters that consume all types.
//首先增加默许的BuiltInConverters,最终增加检测渠道环境时默许回来的数据转化器OptionalConverterFactory
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(platform.defaultConverterFactories());
return new Retrofit(callFactory, baseUrl, unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories), callbackExecutor, validateEagerly);
}
能够看到在build()中做了:查看装备、设置默许装备、创立Retrofit目标,而且在履行build()之前只要baseUrl()是有必要调用来设置拜访地址的,其余办法则是可选的,没有指定就运用默许装备。别的:
- callFactory负责创立HTTP恳求,HTTP恳求被笼统为了okhttp3.Call类,它表明一个已经准备好,能够随时履行的HTTP恳求
- CallAdapter负责把服务器的原始回来数据封装成Retrofit的Call目标(注意和okhttp3.Call区别开来),经过Call建议HTTP恳求,并把从服务器拿到的数据(经过okhttp3.Call完成)转化为接口办法声明的回来类型T(经过Converter<F, T> 完成)
1.5 总结
Retrofit创立实例时首要涉及了以下的装备项:
- 网络恳求地址baseUrl
- 网络恳求履行器工厂callFactory:默许运用OkHttpClient,经过OkHttp处理后续网络恳求和呼应
- 回调办法履行器callbackExecutor:默许运用MainThreadExecutor
- 网络恳求适配器工厂调集callAdapterFactories:默许增加DefaultCallAdapterFactory
- 数据转化器工厂调集converterFactories:默许增加BuiltInConverters和OptionalConverterFactory,BuiltInConverters直接取对应的值并未转化,能够经过设置GsonConverterFactory来用Gson解析json数据
由于运用了建造者形式,所以创立Retrofit实例时并不需要关怀装备细节。
2. 创立网络恳求接口实例
//定义网络恳求的接口类
interface TestApi {
@GET("/.../...")
fun getDataA(): Call<DataBean> //①不运用协程
@GET("/.../...")
suspend fun getDataB(): DataBean //②运用协程
}
//创立网络恳求接口实例
val testApi = retrofit.create(TestApi::class.java)
//调用接口办法①
fun getDataA() {
testApi.getDataA().enqueue(object : Callback<DataBean> {
override fun onResponse(
call: Call<DataBean>,
response: Response<DataBean>
) {
//成功逻辑
}
override fun onFailure(call: Call<DataBean>, t: Throwable) {
//失败逻辑
}
})
}
//调用接口办法②
suspend fun getDataB() {
try {
testApi.getDataB()
//成功逻辑
} catch (e: Exception) {
//失败逻辑
}
}
能够看到恳求接口里的恳求办法类型及恳求url的后半部分是经过注解来标示的,而DataBean是该办法的回来类型(一个自定义的Data类)
别的,在没有给Retrofit增加任何CallAdapterFactory的情况下:
- 接口办法①的回来类型就有必要是Call<?>,不能为其他类型;
- 接口办法②由于用了suspend要害字,挂起了之后就能够无需运用Call类型回来成果,而是直接回来数据类目标。
接口创立完之后便是调用Retrofit的create办法来生成接口的动态署理目标,下面就来看看详细是怎样完成动态署理的。
2.1 create办法
public <T> T create(final Class<T> service) {
//①验证接口合法性
validateServiceInterface(service);
//②生成接口的动态署理
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
//假如该办法是Object的办法则直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
//是默许办法则直接履行默许办法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
//获取办法的对应ServiceMethod目标并调用invoke办法
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
①处的办法除了校验接口之外,还对是否提早解析接口中的所有办法进行了判别:
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);
......//验证接口泛型参数及接口类型
//假如设置了预解析则提早解析接口中的所有办法
if (validateEagerly) {
Platform platform = Platform.get();
for (Method method : service.getDeclaredMethods()) {
if (!platform.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers())) {
loadServiceMethod(method);
}
}
}
}
假如初始化Retrofit实例的时分设置了预解析,就会提早给接口中的每个办法解析生成对应的一个ServiceMethod目标并存入缓存,不然就调用办法的时分再动态解析,详细是怎样解析的看loadServiceMethod这个办法(后边会阐明)
在create办法中首要的代码便是②处的Proxy.newProxyInstance,当把恳求接口类传进create里的时分就会动态生成并回来一个署理目标,而接口办法被调用的时分实践上是由动态署理目标将办法转发到InvocationHandler的invoke办法中处理。由于实践调用的接口办法不是默许办法,那真正调用到的便是loadServiceMethod(method).invoke(args != null ? args : emptyArgs),这也是后续分析的要害入口。
2.2 loadServiceMethod办法
ServiceMethod<?> loadServiceMethod(Method method) {
//从缓存中获取
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
//加锁,创立该办法的ServiceMethod目标并存入缓存
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
接口办法传进loadServiceMethod后优先是从缓存中查对应的ServiceMethod目标,获取到了就直接回来,不然加锁后创立这个办法的ServiceMethod目标,以method为主键存入一个叫serviceMethodCache的map中。
能够看出来同一个接口的办法只会解析一次,每一个调用过的办法都会存在对应的ServiceMethod目标,由于建接口实例的时分传进的是class目标(TestApi::class.java),class目标在进程内单例的,所以获取到的同一个method也是单例的,因此这儿的缓存有效。
这段代码首要是为了拿到一个ServiceMethod目标,而生成ServiceMethod目标是调用了ServiceMethod的parseAnnotations办法,ServiceMethod里边到底是什么东东,parseAnnotations办法详细干了什么,下面持续来扒一扒。
2.3 ServiceMethod类
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//依据办法的注解生成Request的工厂类实例
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
//校验办法的回来类型
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
//生成并回来HttpServiceMethod目标
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
回看2.1中获取的ServiceMethod目标实践上是这儿的HttpServiceMethod目标,调用链路为loadServiceMethod -> ServiceMethod.parseAnnotations -> HttpServiceMethod.parseAnnotations,持续往下看HttpServiceMethod的parseAnnotations办法。
2.4 HttpServiceMethod类parseAnnotations办法
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
//Kotlin协程检测
......
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
//获取办法回来类型
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
......//校验responseType
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
parseAnnotations办法最终回来的是HttpServiceMethod目标,假如对错挂起办法则直接回来CallAdapted,挂起办法而且回来类型为Response则回来SuspendForResponse,不然回来SuspendForBody。
现在了解了Retrofit生成动态署理目标的逻辑,那动态署理是怎样进行网络恳求的和回调又是怎么处理的呢?下一篇将持续分析。