文章目录
一、Retrofit 是什么?
Github的原文是:A type-safe HTTP client for Android and the JVM. 一个适用于Android和JVM的类型安全的HTTP客户端。
在我看来是一个基于OkHttp,通过运用注解和动态代理的方法,实现网络请求的框架。
二、使用步骤(Android代码)
1.引入库
//retrofit版本
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//retrofit的数据适配器,支持Gson、jackson、java8、scalar等等,也可以自定义
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//retrofit的请求适配器,支持java8、rxjava1、rxjava2、rxjava3等等,也可以自定义
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
2.创建Retrofit实例
//配置OkHttpClient,可以参考OkHttp的教程配置项目中需要的功能
private val client by lazy {
OkHttpClient.Builder()
.build()
}
//配置Retrofit
private val retrofit by lazy {
Retrofit.Builder()
//配置baseUrl,可以通过反射等方式动态修改
.baseUrl("https://www.wanandroid.com/")
//配置OkHttpClient客户端
.client(client)
//添加数据适配器工厂,如果不添加,默认工厂是BuiltInConverters(只能处理ResponseBody、Void、Unit类型)
//如果是Java8+/Android API 24+ 还有一个OptionalConverterFactory
.addConverterFactory(GsonConverterFactory.create())
//添加请求适配器工厂,如果不添加,默认工厂是DefaultCallAdapterFactory(处理Call类型)
//如果是Java8+/Android API 24+ 还有一个CompletableFutureCallAdapterFactory
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
3.创建ApiService接口
interface WanAndroidApi {
@GET("article/list/{page}/json")
fun getHomeArticles(@Path("page") page: Int): Call<ArticleData> //默认请求方式
@GET("banner/json")
fun getBanners(): Observable<Response<BannerData>> //基于rxjava2方式,也可以把Response去掉,直接用Observable<BannerData>
@GET("hotkey/json")
suspend fun getHotkeys(): HotkeyData //基于Kotlin协程 挂起函数
}
4.进行网络请求
// 通过动态代理获取接口实例
val wanAndroidApi = retrofit.create(WanAndroidApi::class.java)
// 默认请求方式
val articleDataCall = wanAndroidApi.getHomeArticles(1)
articleDataCall.enqueue(object : Callback<ArticleData> {
override fun onResponse(call: Call<ArticleData>, response: Response<ArticleData>) {
//获得response对象,返回内容为response.body()
}
override fun onFailure(call: Call<ArticleData>, t: Throwable) {
}
})
// 基于rxjava2请求方式
wanAndroidApi.getBanners()
.subscribeOn(Schedulers.newThread())
.subscribe { response ->
//获得response对象,返回内容为response.body()
}
// 基于Kotlin协程请求方式
GlobalScope.launch {
val hotkeyData = wanAndroidApi.getHotkeys() //获得HotKeyData对象
}
三、源码分析
1.动态代理获取ApiService接口实例
从demo中可以看到ApiService接口是通过Retrofit的create()方法获取的,使用的是Java中动态代理的方法,通过Proxy.newProxyInstance动态获取
Retrofit.class
//获取ApiService实例
public <T> T create(final Class<T> service) {
//检查service是否为Interface以及service及其父接口是否有泛型
validateServiceInterface(service);
//动态代理返回接口对象
return (T)
Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] {service},
new InvocationHandler() {、
//获取平台信息,此处获取的是Android平台,Platform中定义了一些默认值和方法,如默认的CallAdapterFactory、
//ConverterFactory、CallBackExecutor,还有处理接口default方法的方法
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 {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
args = args != null ? args : emptyArgs;
// 判断接口里定义的方法是否是default方法,如果是,按照default实现的内容调用,否则,
// 调用loadServiceMethod().invoke(),其中loadServiceMethod()是获取方法
// 从Java8开始支持接口中定义default方法和static方法
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
//获取接口方法,此处对接口的方法做了一个缓存,为了确保线程安全,使用ConcurrentHashMap来存储
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
//如果缓存中没有,则通过ServiceMethod的方法来获取
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
2.接口方法的解析、获取
ServiceMethod 是一个抽象类,用来获取解析Retrofit中定义的注解,组合成方法,通过抽象方法invoke(),返回接口方法的调用,实现类为HttpServiceMethod<ResponseT, ReturnT>
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
//获取请求信息工厂类
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
......
//转给子类HttpServiceMethod获取
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
//调用接口定义的方法,由子类HttpServiceMethod实现,其实就是调用OkHttp进行网络请求
abstract @Nullable T invoke(Object[] args);
}
先看RequestFactory如何获取
RequestFactory.class
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
//通过建造者模式返回了RequestFactory对象
return new Builder(retrofit, method).build();
}
RequestFactory的内部类Builder.class
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
//解析方法的注解信息
parseMethodAnnotation(annotation);
}
......
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0, lastParameter = parameterCount - 1; p < parameterCount; p++) {
//解析参数的注解信息
parameterHandlers[p] =
parseParameter(p, parameterTypes[p], parameterAnnotationsArray[p], p == lastParameter);
}
......
return new RequestFactory(this);
}
//解析附加在方法上的注解信息,获取请求方式、路径、Header、
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else ......
}
//解析参数的注解信息,存储到ParameterHandler中
private @Nullable ParameterHandler<?> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction =
parseParameterAnnotation(p, parameterType, annotations, annotation);
......
}
}
......
//判断是否是协程方法 挂起函数
if (Utils.getRawType(parameterType) == Continuation.class) {
isKotlinSuspendFunction = true;
return null;
}
......
}
return result;
}
通过RequestFactory.Builder类实现了RequestFactory各个属性的赋值。然后我们看HttpServiceMethod怎么获取接口方法的。
HttpServiceMethod.class
//这里解释一下ResponseT和ReturnT,以Call<ArticleData>为例
//ReturnT是Call<ArticleData>,ResponseT为ArticleData
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
//获取方法的ReturnType
Annotation[] annotations = method.getAnnotations();
Type adapterType;
//区分是否为Kotlin协程
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType =
Utils.getParameterLowerBound(
0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
//获取请求适配器,通过adapterType,也就是返回类型,
//去最开始添加的CallAdaperFactory的数组中匹配对应的CallAdapter,如Observable<T>对应RxJava2CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
......
//获取response数据转换器,通过responseType,去最开始添加的ConverterFactory的数组中匹配对应的Converter
//如我们添加的GsonConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
//通过之前获取的requestFactory,callFactory,responseConverter,callAdapter 四个值
//获取接口的方法,此处HttpServiceMethod细分了3个子类型
if (!isKotlinSuspendFunction) { // 非Ktolin协程方式
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) { //协程带Response类型
//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>) //协程只返回Body类型
new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
至此,接口方法的获取已经解释清楚了。
3.接口的调用
获取到接口方法后,当我们通过ApiService的实力去调用方法时,如wanAndroidApi.getHomeArticles(1).enqueue(…),就会调用我们获取的ServiceMethod对象的invoke方法,即HttpServiceMethod的invoke方法
HttpServiceMethod.class
HttpServiceMethod(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter) {
this.requestFactory = requestFactory;
this.callFactory = callFactory;
this.responseConverter = responseConverter;
}
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
protected abstract @Nullable ReturnT adapt(Call<ResponseT> call, Object[] args);
可以看到,这里生成了一个OkHttpCall对象,是Retrofit的Call接口的实现类,然后通过抽象的adapt方法进行适配,即交给3个子类CallAdapted<ResponseT, ReturnT>、SuspendForResponse、SuspendForBody 去实现。我们以CallAdapted子类为例
CallAdapted.class
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
然后发现又转给了CallAdapter去实现,以我们的第一个接口为例,ReturnType是Call,对应的CallAdapter是由DefaultCallAdapterFactory的get方法生成的,如下:
DefaultCallAdapterFactory.class
@Nullable
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
} else if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException("Call return type must be parameterized as Call<Foo> or Call<? extends Foo>");
} else {
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType)returnType);
final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class) ? null : this.callbackExecutor;
//返回CallAdapter实例
return new CallAdapter<Object, Call<?>>() {
public Type responseType() {
return responseType;
}
public Call<Object> adapt(Call<Object> call) {
//此处使用代理模式,将OkHttpCall功能代理到了ExecutorCallbackCall类中。
return (Call)(executor == null ? call : new ExecutorCallbackCall(executor, call));
}
};
}
}
所以,当我们调用wanAndroidApi.getHomeArticles(1).enqueue(…)时,其实最后是走到了ExecutorCallbackCall的enqueue(…)方法。
ExecutorCallbackCall.class
//异步请求
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
//此处的delegate其实是OkHttpCall
this.delegate.enqueue(new Callback<T>() {
public void onResponse(Call<T> call, Response<T> response) {
//通过配置的callbackExecutor将线程切回到MainThread
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
if (ExecutorCallbackCall.this.delegate.isCanceled()) {
//此处的callback就是我们调用wanAndroidApi.getHomeArticles(1).enqueue(...)时传入的callback
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
public void onFailure(Call<T> call, Throwable t) {
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
callback.onFailure(ExecutorCallbackCall.this, t);
});
}
});
}
当然,此处只是针对Call这种默认的请求方式来解释源码,我们添加的Rxjava2CallAdapter或者其他的CallAdapter会有各自的adapt方法去实现请求,但都是代理了OkHttpCall去实现网络请求的。而OkHttpCall里其实是封装了OkHttp去进行的请求。
OkHttpCall.class
//生成最终网络请求对象其实是okhttp3.Call
private okhttp3.Call createRawCall() throws IOException {
okhttp3.Call call = callFactory.newCall(requestFactory.create(args));//通过RequestFactory生成OkHttp的Request
if (call == null) {
throw new NullPointerException("Call.Factory returned null.");
}
return call;
}
当我们配置了Converter后,OkHttpCall中会通过Converter转换成我们需要的Response
OkHttpCall.class
//解析OkHttp访问接口返回的数据
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
......
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody);
try {
//通过我们设置的Converter提供的responseConverter去转换返回数据,返回我们需要的类型
T body = responseConverter.convert(catchingBody);
return Response.success(body, rawResponse);
} catch (RuntimeException e) {
......
}
}
至此,我们完成了对Retrofit框架的源码解析。
根据对源码的解析我们发现这个框架的重中之重就是CallAdapter的adapt(),这是真正实现网络请求的关键点。
总结
根据源码分析,总结一下Retrofit中使用的设计模式吧,对我们以后设计代码也有所帮助。
- 构造者模式(Builder) : 例如Retrofit的Builder。
我们通过链式调用和步骤化的方式创建复杂对象。该模式将对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。 - 抽象工厂模式:例如CallAdapter.Factory。
通常用于创建一组相关或依赖的对象,这些对象共同完成一项任务或工作。通过使用抽象工厂模式,可以确保创建的对象家族在逻辑上是一致的,并且能够相互协作。 - 适配器模式:例如CallAdapter
用于解决两个不兼容接口之间的兼容性问题。适配器模式将一个类的接口转换成客户端所期望的另一个接口,从而使得原本由于接口不兼容而无法在一起工作的类能够协同工作。 - 代理模式:例如ExecutorCallbackCall
可以用来控制对对象的访问、提供额外的功能、保护真实对象
以上内容属于个人见解,如有不对请留言指正,谢谢。