Retrofit
Retrofit通过组合各种设计模式,封装网络请求接口的框架,具体的请求交给Okhttp去完成。
简单实现
Retrofit对象的配置需要数据序列化、线程调度、适配器等一系列的配置。具体配置可以自由设置,需要注意的是配置数据转换器时,要指定对应的转换器。不然数据序列化时可能会报错。
val client = OkHttpClient.Builder()
.addInterceptor(LoggingInterceptor())
.build()
val retrofit = Retrofit.Builder()
.client(client)
.baseUrl(HttpService.HttpUrl.url)
.addCallAdapterFactory(KotlinCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.addConverterFactory(JaxbConverterFactory.create())
.build()
fun request() {
retrofit.create(HttpService::class.java)
.request1()
.enqueue(object : Callback<ResponseData<List<WxArticle>>> {
override fun onResponse(call: Call<ResponseData<List<WxArticle>>>, response: Response<ResponseData<List<WxArticle>>>) {
Log.i("MDY", "onResponse=" + Thread.currentThread().name)
Log.i("MDY", "onResponse: " + response.body().toString())
}
override fun onFailure(call: Call<ResponseData<List<WxArticle>>>, t: Throwable) {
Log.i("MDY", "onFailure: ")
}
})
}
复制代码
Retrofit创建后,具体的网路请求需要调用
create
方法,动态生成一个代理类来实现对应的网络请求。
create
Android中创建一个委托类Service时,由于Service是一个接口,请求方法一定是
public abstract
类型,所以Retrofit中
create
方法创建的动态代理类在调用Service中对应的请求方法时,最终会执行到
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) {
//解析Method
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
复制代码
Retrofit中使用一个Map集合来保存已经解析过的请求方法并封装为对应的实现类
ServiceMethod
:
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>()
复制代码
若请求接口时第一次被调用,会通过
ServiceMethod
的
parseAnnotations
来解析方法。首先会调用
RequestFactory
的
parseAnnotations
方法解析方法的注解、参数注解、返回类型等:
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
//......判断返回类型是否合法
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
复制代码
HttpServiceMethod
本身也是一个抽象类,
parseAnnotations
方法中会获取对应的
CallAdapter、Converter和callFactory
对象,最后创建一个CallAdapted对象返回。
createCallAdapter
private static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) {
try {
return (CallAdapter<ResponseT, ReturnT>) retrofit.callAdapter(returnType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create call adapter for %s", returnType);
}
}
复制代码
调用Retrofit的
callAdapter
方法,最终会回调到我们在创建Retrofit时传入的
CallAdapterFactory
中,并调用对应的
get
方法获取
CallAdapter
对象。
createResponseConverter
private static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations();
try {
return retrofit.responseBodyConverter(responseType, annotations);
} catch (RuntimeException e) { // Wide exception range because factories are user code.
throw methodError(method, e, "Unable to create converter for %s", responseType);
}
}
复制代码
调用Retrofit的
responseBodyConverter
方法,最终会回调到我们在创建Retrofit时传入的
Converter.Factory
中,并调用对应的
responseBodyConverter
方法获取
Converter<ResponseBody, ?>
对象。在后面的
OkHttpCall
中获取响应体后会调用已创建的
Converter
来序列化数据。
callFactory
okhttp3.Call.Factory callFactory = retrofit.callFactory;
复制代码
Call.Factory就是我们传递到Retrofit中的OkhttpClient对象。
CallAdapted
ServiceMethod
和
HttpServiceMethod
都是抽象类,我们需要的是一个具体的实现类,所以CallAdapted来了。CallAdapted继承自
HttpServiceMethod
并保存了以下对象:
- requestFactory 解析请求方法后的数据保存类。
- callFactory OkhttpClient对象,用于具体的网络请求。
- responseConverter 数据转换器,用于序列化请求返回的响应。
- callAdapter 调用适配器,或区域一个call的对象,可以实现请求的发起和线程的调度。
执行到了这里,我们回到最开始的
create
方法中,当通过动态代理调用请求方法时,执行到
loadServiceMethod
最终会获取到一个
CallAdapted
对象。紧接着调用
invoke
方法,
CallAdapted
中并没有实现该方法,具体的在
HttpServiceMethod
中:
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return