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 adapt(call, args);
}
这里出现一个OkHttpCall
类,这个类用于具体的网络请求,内部创建了OKhttp中对应的RealCall
对象,并添加了同步和异步的方法,具体的使用和Okhttp区别不大。由于本文是分析Retrofit的原理流程,所以不多加解释,有兴趣的可以进去看看。紧接着会回调CallAdapted
的
adapt
方法:
@Override protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
这里的CallAdapter
是我们在HttpServiceMethod
中创建的callAdapter
,像我们使用到RxJava的话,这里传递的就是对应的RxJavaCallAdapterFactory
对象内部返回的CallAdapter
。在调用adapt
方法时,将invoke
方法中创建的OkHttpCall
传递进去,因为OkHttpCall中封装了对应的Realcall
,所以不难猜测,具体的网络请求和解析肯定在对应的CallAdapter
实现类中。
CallAdapter
CallAdapter
称为调用适配器,在创建Retrofit对象时,我们可以调用addCallAdapterFactory(KotlinCallAdapterFactory())
传入一个指定的调用适配工厂类,用于创建具体的调用适配器。具体的工厂类需要继承Factory
类,通过get方法返回一个CallAdapter对象。
public interface CallAdapter<R, T> {
// 请求方法返回类型
Type responseType();
// 返回一个OkHttpCall的委托实例,或者执行请求
T adapt(Call<R> call);
//作为一个抽象工厂,返回一个调用适配器
abstract class Factory {
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
......
}
}
Retrofit对RxJava做了适配,提供了RxJavaCallAdapterFactory
工厂类。若不做设置的话,Retrofit提供了默认的工厂类实现DefaultCallAdapterFactory
。在上文我们提到过当调用Retrofit的动态代理来调用对应的网络请求时,会最终回调到callAdapter
的adapt
方法并传递一个OkHttpCall实例对象。获取到了该实例对象,我们就可以执行具体的网络请求,下面我们就实现一个简单的调用适配器工厂类和对应的适配器:
class KotlinCallAdapterFactory : CallAdapter.Factory() {
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<*, *>? {
val rawType = getRawType(returnType)
check(rawType !is Call<*>){
error("返回类型不对")
}
return KotlinCallAdapter(returnType)
}
}
class KotlinCallAdapter(private val returnType: Type) : CallAdapter<Any, Any> {
override fun responseType(): Type {
return getParameterUpperBound(0, returnType as ParameterizedType)
}
override fun adapt(call: Call<Any>): Any {
return call
}
private fun getParameterUpperBound(index: Int, type: ParameterizedType): Type {
val types = type.actualTypeArguments
require(!(index < 0 || index >= types.size)) { "Index " + index + " not in range [0," + types.size + ") for " + type }
val paramType = types[index]
return if (paramType is WildcardType) {
paramType.upperBounds[0]
} else paramType
}
}
实现了KotlinCallAdapterFactory
对象后,我们可以直接使用:
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自带的DefaultCallAdapterFactory
和Rxjava的RxJavaCallAdapterFactory
工厂类,都可以具体的参考并体会人家实现的细节和思路。
在DefaultCallAdapterFactory中通过Handler将返回数据post到主线程。
本来到这里Retrofit的流程就分析的差不多了,但我觉得还得加入一个Converter
,该接口的作用在于将HTTP交互相关的请求、响应转换成具体的对象。
Converter
Converter可以被认为是数据转换器,具体的数据类型比如json、xml等需要对应的转换器去实现。在创建Retrofit对象时,我们可以通过addConverterFactory(GsonConverterFactory.create())
方法传递不同的数据解析器,可以传递多个,内部会根据数据类型来解析数据。Retrofit中数据转换器的实现采用抽象工厂来实现,具体的工厂类的创建需要继承Factory
类,并实现对应的responseBodyConverter
和requestBodyConverter
方法。
解析请求参数时,会调用requestBodyConverter
方法获取一个Converter
实例,调用convert方法转换成一个RequestBody请求体。OkHttpCall
中获取到响应时,会调用responseBodyConverter
方法获取一个Converter
实例,调用convert方法将ResponseBody转换成对应的返回数据类型。
public interface Converter<F, T> {
@Nullable T convert(F value) throws IOException;
abstract class Factory {
public @Nullable Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
return null;
}
public @Nullable Converter<?, String> stringConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return null;
}
......
}
}
看到上面是不是感觉非常类似,没错Converter
跟CallAdapter
的实现设计一致,都是采用抽象工厂的方式,方便我们自由设置数据转换器和调用适配器,实现了高内聚低耦合的特点。
Converter
基本情况下不需要我们去自定义,Retrofit中提供了丰富的Converter
实现类:
- GsonConverterFactory Gson转换器,是用于json数据格式。
- SimpleXmlConverterFactory Xml转换器,已废弃。
- JaxbConverterFactory 新的Xml转换器。 还有其他的类型,都可以看一看 Converter转换器实现类
Retrofit中提供了一种转换器的写法,通过在接口中声明请求的返回值类型,来动态制定转换器: JsonAndXmlConverters
总结
Retrofit中一次完整的流程包括以下几个步骤:
- Retrofit的创建,可以配置OkhttpClient、CallAdapter适配器、Converter转换器等。
- 调用create方法动态生成代理类发起网络请求,内部会调用到
loadServiceMethod
方法获取一个ServiceMethod
对象。 - 经过
ServiceMethod
的parseAnnotations
来解析请求方法的注解、参数注解、返回类型等数据传递给HttpServiceMethod
. HttpServiceMethod
中会根据method、返回类型、注解等获取CallAdapter
和Conveter
实现类,并返回一个CallAdapted
对象。- 回调
CallAdapted
的invoke
方法,获取网络请求的封装类OkHttpCall
对象。 OkHttpCall
对象会传递给CallAdapter
对象来发起网络请求,并在OkHttpCall
中调用Conveter
解析响应。
Retrofit中通过大量的设计模式,将HTTP
请求抽象成Java接口。通过注解 来描述和配置网络请求。通过动态代理来实现Service接口方法。通过抽象工厂模式,我们可以设置CallAdapter
来实现请求的发起、线程的调度等操作。可以说Retrofit的代码体现了一种设计之美,对于源码的阅读,和设计模式的理解有很大的帮助。最后就到这里吧,后面我会随着Retrofit来进一步学习他的设计模式。