你在使用 Retrofit 的时候,是否会有如下几点疑惑?
什么是动态代理?
整个请求的流程是怎样的?
底层是如何用 OkHttp 请求的?
方法上的注解是什么时候解析的,怎么解析的?
Converter 的转换过程,怎么通过 Gson 转成对应的数据模型的?
CallAdapter 的替换过程,怎么转成 RxJava 进行操作的?
如何支持 Kotlin 协程的 suspend 挂起函数的?
关于 Kotlin 协程请求网络,首先写一个 Demo 来看一下用协程是怎么进行网络请求的,然后会再具体分析怎么转换成 Kotlin 的协程的请求
我会在文章中,通过源码,逐步解开疑惑,并且在最后文章结尾会再次总结,回答上面的几个问题。
友情提示,本文略长但是没有废话,实打实的干货,学习需要耐心
Retrofit和 OkHttp是目前最广泛使用的网络请求库了,所以有必要了解它的源码,学习它的优秀的代码与设计,来提升自己。
本文的整体思路
首先先看一下 Retrofit 的基本用法,根据示例代码,作为分析源码的依据,以及分析源码的入口,来一步一步看一下 Retrofit 的工作机制。
本文的依赖
implementation 'com.squareup.okhttp3:okhttp:4.8.1'implementation 'com.squareup.retrofit2:retrofit:2.9.0'implementation 'com.squareup.retrofit2:converter-gson:2.5.0'implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.2'implementation 'com.google.code.gson:gson:2.8.6'implementation 'io.reactivex.rxjava3:rxjava:3.0.0'implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'复制代码
Retrofit:A type-safe HTTP client for Android and Java。一个类型安全的 Http 请求的客户端。
底层的网络请求是基于 OkHttp 的,Retrofit 对其做了封装,提供了即方便又高效的网络访问框架。
class RetrofitActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) //初始化一个Retrofit对象
val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build() //创建出GitHubApiService对象
val service = retrofit.create(GitHubApiService::class.java) //返回一个 Call 对象
val repos = service.listRepos("octocat") //调用 enqueue 方法在回调方法里处理结果
repos.enqueue(object : Callback<List<Repo>?> {
override fun onFailure(call: Call<List<Repo>?>, t: Throwable) {
t.printStackTrace()
}
override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>) { "response.code() = ${response.code()}".logE()
}
})
}
}
复制代码
//自己定义的 API 请求接口interface GitHubApiService { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String?): Call<List<Repo>>
}
复制代码
以上就是 Retrofit 的基本用法。
没什么好讲的,写这个例子就是为了分析源码做准备,有一个源码分析的入口。
先看几个表面上的类
create 方法进行实例化接下来重点来了,进行源码分析。
分析的入口是我们代码例子中的
repos.enqueue(object : Callback<List<Repo>?> {…})方法
点进去,看到是 Call 的
enqueue方法
public interface Call<T> extends Cloneable { void enqueue(Callback<T> callback);
}
复制代码
这是一个接口,是我们 GitHubApiService 接口中定义的
listRepos 方法中返回的 Call 对象,现在就要看GitHubApiService 的初始化,以及具体返回的是
Call 对象是谁。
然后重点就要看
retrofit.create(GitHubApiService::class.java) 方法,来看下 GitHubApiService 具体是怎么创建的,以及 Call 对象的实现类
//Retrofit.javapublic <T> T create(final Class<T> service) { //1
validateServiceInterface(service); //2
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 { // 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; return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
复制代码
注释 1:这个方法,就是验证我们定义的 GitHubApiService 是一个接口,且不是泛型接口,并且会判断是否进行方法的 提前验证,为了更好的把错误暴露的编译期,这个不是我们的重点内容,具体代码就不看了。
注释 2 :是一个动态代理的方法,来返回 GitHubApiService 的实例
动态代理?嗯?什么是动态代理,接下来,我就写一个具体的例子来展示一个动态代理的具体用法,以及什么是动态代理?
先插播一段动态代理代码,这个是理解 Retrofit 的工作机制所必须的。
下面是一个 Java 项目,模拟一个 Retrofit 的请求过程
//模拟 Retrofit,定义 API 请求接口public interface GitHubApiService { void listRepos(String user);
}
复制代码
public class ProxyDemo { //程序的入口方法
public static void main(String[] args) { //通过动态代理获取 ApiService 的对象
GitHubApiService apiService = (GitHubApiService) Proxy.newProxyInstance(
GitHubApiService.class.getClassLoader(), new Class[]{GitHubApiService.class}, new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method = " + method.getName() + " args = " + Arrays.toString(args)); return null;
}
});
System.out.println(apiService.getClass()); //调用 listRepos 方法
apiService.listRepos("octcat");
}
}
复制代码
执行
main 方法
当我们调用
apiService.listRepos("octcat");方法时,打印出来如下结果
class com.sun.proxy.$Proxy0method = listRepos args = [octcat] 复制代码
可以看到当我们调用
listRepos方法的时候,InvocationHandler 的
invoke方法中拦截到了我们的方法,参数等信息。
Retrofit 的原理其实就是这样,拦截到方法、参数,再根据我们在方法上的注解,去拼接为一个正常的OkHttp 请求,然后执行。
日志的第一行,在运行时这个类一个
$Proxy0的类。实际上,在运行期 GitHubApiService 的接口会动态的创建出
实现类也就是这个
$Proxy0类,它大概长下面这个样子。
我做了一个点改动,方便查看,本质上都是一样的
class $Proxy0 extends Proxy implements GitHubApiService { protected $Proxy0(InvocationHandler h) { super(h);
} @Override
public void listRepos(String user) {
Method method = Class.forName("GitHubApiService").getMethod("listRepos", String.class); super.h.invoke(this, method, new Object[]{user});
}
}
复制代码
我们在调用
listRepos方法的时候,实际上调用的是 InvocationHandler 的
invoke 方法。
invoke 方法。invoke方法。现在解决了第一个疑问: 什么是动态代理
好的,动态代理已经知道是啥了,回到我们
retrofit.create(GitHubApiService::class.java)方法
//Retrofit.javapublic <T> T create(final Class<T> service) {
validateServiceInterface(service); return (T)
Proxy.newProxyInstance(
service.getClassLoader(),//1
new Class<?>[] {service},//2
new InvocationHandler() {//3
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.
//4
if (method.getDeclaringClass() == Object.class) { return method.invoke(this, args);
}
args = args != null ? args : emptyArgs; //5
return platform.isDefaultMethod(method)
? platform.invokeDefaultMethod(method, service, proxy, args)
: loadServiceMethod(method).invoke(args);
}
});
}
复制代码
注释 1:获取一个 ClassLoader 对象
注释 2:GitHubApiService 的字节码对象传到数组中去,也即是我们要代理的具体接口。
注释 3:InvocationHandler 的
invoke 是关键,从上面动态代理的 Demo 中,我们知道,在GitHubApiService声明的
listRepos方法在调用时,会执行 InvocationHandler 的
invoke的方法体。
注释 4:因为有代理类的生成,默认继承 Object 类,所以如果是 Object.class 走,默认调用它的方法
注释 5:如果是默认方法(比如 Java8 ),就执行 platform 的默认方法。
否则执行
loadServiceMethod方法的
invoke方法
loadServiceMethod(method).invoke(args);这个方法是我们这个 Retrofit
最关键的代码,也是分析的重点入口
我们先看
loadServiceMethod方法返回的是什么对象,然后再看这个对象的
invoke 方法
//Retrofit.javaprivate final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method) { //1
ServiceMethod<?> result = serviceMethodCache.get(method); if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method); if (result == null) { //2
result = ServiceMethod.parseAnnotations(this, method); //3
serviceMethodCache.put(method, result);
}
} return result;
}
复制代码
注释 1:从 ConcurrentHashMap 中取一个 ServiceMethod 如果存在直接返回
注释 2:通过
ServiceMethod.parseAnnotations(this, method);方法创建一个 ServiceMethod 对象
注释 3:用 Map 把创建的 ServiceMethod 对象缓存起来,因为我们的请求方法可能会调用多次,缓存提升性能。
看一下
ServiceMethod.parseAnnotations(this, method);方法具体返回的对象是什么,然后再看它的
invoke 方法
这个方法接下来还会看,这里我们只看现在需要的部分。
//ServiceMethod.javastatic <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
... //1
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
复制代码
返回的是一个 HttpServiceMethod对象,那么接下来看下它的 invoke 方法
//HttpServiceMethod.java@Overridefinal @Nullable ReturnT invoke(Object[] args) { //1
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); //2
return adapt(call, args);
}
复制代码
注释 1:创建了一个Call对象,是 OkHttpCall,这个不就是在 GitHubApiService 这个接口声明的 Call 对象吗?
然后再看 OkHttpCall 的
enqueue方法,不就知道是怎么进行请求,怎么回调的了吗?
注释 2:是一个 adapt 方法,在不使用 Kotlin 协程的情况下,其实调用的是子类 CallAdapted 的
adapt,这个会在下面具体分析,包括 Kotlin 协程的 suspend 函数
现在我们已经知道了 GitHubApiService 接口中定义的
listRepos中的 Call 对象,是 OkHttpCall,接下里看OkHttpCall 的
enqueue 方法
这段代码比较长,但这个就是这个请求的关键,以及怎么使用 OkHttp 进行请求的,如果解析 Response 的,如何回调的。
//OkHttpCall.java@Overridepublic void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null"); //1
okhttp3.Call call;
Throwable failure; synchronized (this) { if (executed) throw new IllegalStateException("Already executed.");
executed = true;
call = rawCall;
failure = creationFailure; if (call == null && failure == null) { try { //2
call = rawCall = createRawCall();
} catch (Throwable t) {
throwIfFatal(t);
failure = creationFailure = t;
}
}
} if (failure != null) {
callback.onFailure(this, failure); return;
} if (canceled) {
call.cancel();
} //3
call.enqueue( new okhttp3.Callback() { @Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response; try { //4
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e); return;
} try { //5
callback.onResponse(OkHttpCall.this, response);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
} @Override
public void onFailure(okhttp3.Call call, IOException e) {
callFailure(e);
} private void callFailure(Throwable e) { try { //6
callback.onFailure(OkHttpCall.this, e);
} catch (Throwable t) {
throwIfFatal(t);
t.printStackTrace(); // TODO this is not great
}
}
});
}
复制代码
注释 1:声明一个 okhttp3.Call 对象,用来进行网络请求
注释 2:给 okhttp3.Call 对象进行赋值,下面会具体看代码,如何创建了一个 okhttp3.Call 对象
注释 3:调用 okhttp3.Call 的
enqueue 方法,进行真正的网络请求
注释 4:解析响应,下面会具体看代码
注释 5:成功的回调
注释 6:失败的回调
到现在,我们文章开头两个疑问得到解释了
整个请求的流程是怎样的?
底层是如何用 OkHttp 请求的?
我们还要看下一个 okhttp3.Call 对象是怎么创建的,我们写的注解参数是怎么解析的,响应结果是如何解析的,也就是我们在 Retrofit 中配置
addConverterFactory(GsonConverterFactory.create())是如何直接拿到数据模型的。
看下
call = rawCall = createRawCall();方法
//OkHttpCall.javaprivate final okhttp3.Call.Factory callFactory;private okhttp3.Call createRawCall() throws IOException { //1 callFactory是什么
okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null.");
} return call;
}
复制代码
通过 callFactory 创建的(callFactory应该是 OkHttpClient),看一下 callFactory 的赋值过程
//OkHttpCall.javaOkHttpCall(
RequestFactory requestFactory, Object[] args,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, T> responseConverter) { this.requestFactory = requestFactory; this.args = args; //通过 OkHttpCall 构造直接赋值
this.callFactory = callFactory; this.responseConverter = responseConverter;
}
复制代码
在 OkHttpCall 构造中直接赋值,那接下来就继续看 OkHttpCall 的初始化过程
//HttpServiceMethod.javaprivate final okhttp3.Call.Factory callFactory;@Overridefinal @Nullable ReturnT invoke(Object[] args) { //在 OkHttpCall 实例化时赋值, callFactory 是 HttpServiceMethod 的成员变量
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter); return adapt(call, args);
}//callFactory 是在 HttpServiceMethod 的构造中赋值的HttpServiceMethod(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter) { this.requestFactory = requestFactory; //通过 HttpServiceMethod 构造直接赋值
this.callFactory = callFactory; this.responseConverter = responseConverter;
}
复制代码
发现 callFactory 的值是在创建 HttpServiceMethod 时赋值的,继续跟!
在 7.2 小节,有一行代码
HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);我们没有跟进去,现在看一下
HttpServiceMethod 是怎么创建的
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) { boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false; //1
okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { //2
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);
}
}
复制代码
注释 1:callFactory 的值是从 Retrofit 这个对象拿到的
注释 2:如果不是 Kotlin 的挂起函数,返回是的 CallAdapted 对象
static final class CallAdapted<ResponseT, ReturnT> extends HttpServiceMethod<ResponseT, ReturnT> {}
复制代码
CallAdapted 是 HttpServiceMethod 的子类,会调用
adapt方法进行 CallAdapter 的转换,我们后面会详细看。
继续看 Retrofit 的 callFactory 的值Retrofit是通过Builder构建的,看下Builder类
//Retrofit.javapublic static final class Builder { public Retrofit build() {
okhttp3.Call.Factory callFactory = this.callFactory; if (callFactory == null) { //1
callFactory = new OkHttpClient();
} return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
}
复制代码
原来 callFactory 实际是一个 OkHttpClient 对象,也就是 OkHttpClient 创建了一个 Call 对象,嗯就是 OKHttp 网络请求的那一套。
在创建okhttp3.Call 对象的
callFactory.newCall(requestFactory.create(args));方法中的
requestFactory.create(args)方法会返回一个 Request 的对象,这个我们也会在下面看是如何构造一个 OkHttp 的 Request 请求对象的。
看
ServiceMethod.parseAnnotations(this, method);方法
//ServiceMethod.javastatic <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { //1
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
... //2
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
复制代码
注释 1:通过 RequestFactory 解析注解,然后返回 RequestFactory 对象
注释 2:把 RequestFactory 对象往 HttpServiceMethod 里面传递,下面会具体看 RequestFactory 对象具体干什么用了?
继续跟代码
RequestFactory.parseAnnotations
//RequestFactory.javafinal class RequestFactory { static RequestFactory parseAnnotations(Retrofit retrofit, Method method) { //看build方法
return new Builder(retrofit, method).build();
} //build方法
RequestFactory build() { //1
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
.... return new RequestFactory(this);
}
}
复制代码
遍历 GitHubApiService 这个 API 接口上定义的方法注解,然后解析注解
继续跟代码
parseMethodAnnotation
//RequestFactory.javaprivate 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 if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
}
.... else if (annotation instanceof Multipart) { if (isFormEncoded) { throw methodError(method, "Only one encoding annotation is allowed.");
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) { if (isMultipart) { throw methodError(method, "Only one encoding annotation is allowed.");
}
isFormEncoded = true;
}
}
复制代码
就是解析方法上的注解,来存到 RequestFactory 的内部。
其实 RequestFactory 这个类还有
parseParameter 和
parseParameterAnnotation这个就是解析方法参数声明上的具体参数的注解,会在后面分析 Kotlin suspend 挂起函数具体讲。
总之:具体代码就是分析方法上注解上面的值,方法参数上,这个就是细节问题了
总结就是:分析方法上的各个注解,方法参数上的注解,最后返回 RequestFactory 对象,给下面使用。
Retrofit 的大框架简单,细节比较复杂。
RequestFactory 对象返回出去,具体干嘛用了?大胆猜一下,解析出注解存到 RequestFactory 对象,这个对象身上可有各种请求的参数,然后肯定是类创建 OkHttp 的 Request请求对象啊,因为是用 OkHttp 请求的,它需要一个 Request 请求对象
下面我就用一个代码块贴了,看着更直接,我会具体表明属于哪个类的
//ServiceMethod.javastatic <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) { //解析注解参数,获取 RequestFactory 对象
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method); //把 RequestFactory 对象传给 HttpServiceMethod
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}//注意换类了//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
okhttp3.Call.Factory callFactory = retrofit.callFactory; //不是 Kotlin 的挂起函数
if (!isKotlinSuspendFunction) { //把requestFactory传给 CallAdapted
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
....
}//HttpServiceMethod.java//CallAdapted 是 HttpServiceMethod 的内部类也是 HttpServiceMethod 的子类CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) { //这里把 requestFactory 传给 super 父类的构造参数里了,也就是 HttpServiceMethod
super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter;
}//HttpServiceMethod.javaHttpServiceMethod(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter) { // HttpServiceMethod 的 requestFactory 成员变量保存这个 RequestFactory 对象
this.requestFactory = requestFactory; this.callFactory = callFactory; this.responseConverter = responseConverter;
}//因为会调用 HttpServiceMethod 的 invoke 方法//会把这个 RequestFactory 对象会继续传递给 OkHttpCall 类中//注意换类了//OkHttpCall.javaOkHttpCall(
RequestFactory requestFactory,
Object[] args,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, T> responseConverter) { //给 OkHttpCall 的requestFactory成员变量赋值
this.requestFactory = requestFactory; this.args = args; this.callFactory = callFactory; this.responseConverter = responseConverter;
}
复制代码
经过层层传递 RequestFactory 这个实例终于是到了 HttpServiceMethod 类中,最终传到了 OkHttpCall 中,那这个 RequestFactory 对象在什么时候使用呢? RequestFactory 会继续在OkHttpCall中传递,因为 OkHttpCall 才是进行请求的。
在OkHttpCall的 创建 Call 对象时
//OkHttpCall.javaprivate okhttp3.Call createRawCall() throws IOException { //1
okhttp3.Call call = callFactory.newCall(requestFactory.create(args)); if (call == null) { throw new NullPointerException("Call.Factory returned null.");
} return call;
}
复制代码
注释 1:调用了
requestFactory.create(args)
注意:此时的RequestFactory的各个成员变量在解析注解那一步都赋值了
//RequestFactory.javaokhttp3.Request create(Object[] args) throws IOException {
...
RequestBuilder requestBuilder = new RequestBuilder(
httpMethod,
baseUrl,
relativeUrl,
headers,
contentType,
hasBody,
isFormEncoded,
isMultipart);
... return requestBuilder.get().tag(Invocation.class, new Invocation(method, argumentList)).build();
}
复制代码
最终 requestFactory 的值用来构造 okhttp3.Request 的对象
以上就是解析注解,构造出okhttp3.Request的对象全过程了。
也就解答了 方法上的注解是什么时候解析的,怎么解析的?这个问题
比如我们在构造 Retrofit 的时候加上
addConverterFactory(GsonConverterFactory.create())这行代码,我们的响应结果是如何通过 Gson 直接解析成数据模型的?
在 OkHttpCall 的
enqueue方法中
//OkHttpCall.java@Overridepublic void enqueue(final Callback<T> callback) {
okhttp3.Call call;
...
call.enqueue( new okhttp3.Callback() { @Override
public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse) {
Response<T> response; try { //1 解析响应
response = parseResponse(rawResponse);
} catch (Throwable e) {
throwIfFatal(e);
callFailure(e); return;
}
}
...
});
}
复制代码
注释 1:通过
parseResponse解析响应返回给回调接口
//OkHttpCall.javaprivate final Converter<ResponseBody, T> responseConverter;Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
ResponseBody rawBody = rawResponse.body();
...
ExceptionCatchingResponseBody catchingBody = new ExceptionCatchingResponseBody(rawBody); try { //1 通过 responseConverter 转换 ResponseBody
T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse);
} catch (RuntimeException e) { // If the underlying source threw an exception, propagate that rather than indicating it was
// a runtime exception.
catchingBody.throwIfCaught(); throw e;
}
}
复制代码
注释 1:通过 responseConverter 调用
convert方法
首先那看 responseConverter 是什么以及赋值的过程,然后再看
convert方法
//OkHttpCall.javaprivate final Converter<ResponseBody, T> responseConverter;
OkHttpCall(
RequestFactory requestFactory,
Object[] args,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, T> responseConverter) { this.requestFactory = requestFactory; this.args = args; this.callFactory = callFactory; //在构造中赋值
this.responseConverter = responseConverter;
}// OkHttpCall 在 HttpServiceMethod 类中实例化//注意换类了//HttpServiceMethod.javaprivate final Converter<ResponseBody, ResponseT> responseConverter;
HttpServiceMethod(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter) { this.requestFactory = requestFactory; this.callFactory = callFactory; //在构造中赋值
this.responseConverter = responseConverter;
}//HttpServiceMethod 在子类 CallAdapted 调用 super方法赋值CallAdapted(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, ReturnT> callAdapter) { //在CallAdapted中调用super赋值
super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter;
}
复制代码
继续看 CallAdapted 的初始化中 responseConverter 的赋值过程
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
...
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations); //1 实例化responseConverter
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { //2 CallAdapted的实例化赋值
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
...
}
复制代码
继续跟代码
createResponseConverter方法
//HttpServiceMethod.javaprivate static <ResponseT> Converter<ResponseBody, ResponseT> createResponseConverter(
Retrofit retrofit, Method method, Type responseType) {
Annotation[] annotations = method.getAnnotations(); try { //调用的是 retrofit的方法
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.javafinal List<Converter.Factory> converterFactories;public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) { //继续跟 nextResponseBodyConverter
return nextResponseBodyConverter(null, type, annotations);
}public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
@Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
... //1 从 converterFactories工厂中遍历取出
int start = converterFactories.indexOf(skipPast) + 1; for (int i = start, count = converterFactories.size(); i < count; i++) {
Converter<ResponseBody, ?> converter =
converterFactories.get(i).responseBodyConverter(type, annotations, this); if (converter != null) { //noinspection unchecked
return (Converter<ResponseBody, T>) converter;
}
}
...
}
复制代码
注释 1:从 converterFactories 遍历取出一个来调用
responseBodyConverter 方法,注意根据 responseType
返回值类型来取到对应的 Converter,如果不为空,直接返回此 Converter 对象
看一下 converterFactories 这个对象的赋值过程
//Retrofit.javafinal List<Converter.Factory> converterFactories;
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.
//通过 Retrofit 的构造赋值,Retrofit的 初始化是通过内部 Builder 类的build方法
this.callAdapterFactories = callAdapterFactories; // Copy+unmodifiable at call site.
this.callbackExecutor = callbackExecutor; this.validateEagerly = validateEagerly;
}//Retrofit.java 内部类 Builder 类的build方法//Builder.java
public Retrofit build() {
... // Make a defensive copy of the converters.
//1
List<Converter.Factory> converterFactories = new ArrayList<>( 1 + this.converterFactories.size() + platform.defaultConverterFactoriesSize()); //2
converterFactories.add(new BuiltInConverters()); //3
converterFactories.addAll(this.converterFactories); //4
converterFactories.addAll(platform.defaultConverterFactories()); return new Retrofit(
callFactory,
baseUrl,
unmodifiableList(converterFactories),
unmodifiableList(callAdapterFactories),
callbackExecutor,
validateEagerly);
}
复制代码
注释 1:初始化 converterFactories 这个 list
注释 2:添加默认的构建的转换器,其实是 StreamingResponseBodyConverter 和 BufferingResponseBodyConverter
注释 3:就是自己添加的转换配置
addConverterFactory(GsonConverterFactory.create())
//Retrofit.java 内部类 Builder.javapublic Builder addConverterFactory(Converter.Factory factory) {
converterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this;
}
复制代码
注释 4:如果是 Java8 就是一个 OptionalConverterFactory 的转换器否则就是一个空的
注意:是怎么找到GsonConverterFactory来调用 Gson 的 convert方法的呢?在遍历converterFactories时会根据 responseType来找到对应的转换器。
具体 GsonConverterFactory 的
convert 方法就是 Gson 的逻辑了,就不是 Retrofit 的重点了。
到现在 Converter 的转换过程,我们也就清楚了。
还有一个问题,我们写的 API 接口是如何支持 RxJava 的
怎么转成 RxJava
比如:我们在初始化一个Retrofit时加入
addCallAdapterFactory(RxJava2CallAdapterFactory.create())这行
//初始化一个Retrofit对象val retrofit = Retrofit.Builder()
.baseUrl("https://api.github.com/") //加入 RxJava2CallAdapterFactory 支持
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
复制代码
加入 RxJava2 的配置支持后,把 RxJava2CallAdapterFactory 存到 callAdapterFactories 这个集合中,记住这一点,下面要用到。
interface GitHubApiService { @GET("users/{user}/repos") fun listReposRx(@Path("user") user: String?): Single<Repo>
}
复制代码
我们就可以这么请求接口了
//创建出GitHubApiService对象val service = retrofit.create(GitHubApiService::class.java)
service.listReposRx("octocat")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ repo -> "response name = ${repo[0].name}".logE()
}, { error ->
error.printStackTrace()
})
复制代码
我们可以在自己定义的 API 接口中直接返回一个 RxJava 的 Single 对象的,来进行操作了。
我们下面就来看下是如何把请求对象转换成一个 Single 对象的
//Retrofit.java 内部类 Builder.javapublic Builder addCallAdapterFactory(CallAdapter.Factory factory) {
callAdapterFactories.add(Objects.requireNonNull(factory, "factory == null")); return this;
}
复制代码
把 RxJava2CallAdapterFactory 存到了callAdapterFactories 这个 list 中了。
接下来我们看下是如何使用 callAdapterFactories 的 RxJava2CallAdapterFactory 中的这个 CallAdapter 的吧
这就要看我们之前看到了一个类了 HttpServiceMethod 的
parseAnnotations之前看过它的代码,只是上次看的是
Converter是如何赋值的也就是第 8.4 小节,这次看 CallAdapter 是如何被赋值使用的。
HttpServiceMethod的
parseAnnotations方法
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
.... //1
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
okhttp3.Call.Factory callFactory = retrofit.callFactory; if (!isKotlinSuspendFunction) { //2
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
}
...
}
复制代码
注释 1:初始化 CallAdapter
注释 2:给
CallAdapted 中的 callAdapter 变量赋值,然后调用它的
adapt 方法。
我们先找到具体 CallAdapter 赋值的对象,然后看它的
adapt就知道了,是如何转换的了
接下来就是跟代码的过程了
//HttpServiceMethod.javaprivate static <ResponseT, ReturnT> CallAdapter<ResponseT, ReturnT> createCallAdapter(
Retrofit retrofit, Method method, Type returnType, Annotation[] annotations) { try { //noinspection unchecked
//调用retrofit的callAdapter方法
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.javapublic CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) { //调用nextCallAdapter
return nextCallAdapter(null, returnType, annotations);
}public CallAdapter<?, ?> nextCallAdapter(
@Nullable CallAdapter.Factory skipPast, Type returnType, Annotation[] annotations) {
... //遍历 callAdapterFactories
int start = callAdapterFactories.indexOf(skipPast) + 1; for (int i = start, count = callAdapterFactories.size(); i < count; i++) { //是具体CallAdapterFactory的 get 方法
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this); if (adapter != null) { return adapter;
}
}
...
}
复制代码
遍历 callAdapterFactories 根据 returnType类型 来找到对应的 CallAdapter 返回
比如:我们在 GitHubApiService 的 returnType 类型为 Single,那么返回的就是 RxJava2CallAdapterFactory 所获取的 CallAdapter
interface GitHubApiService { @GET("users/{user}/repos") fun listReposRx(@Path("user") user: String?): Single<Repo>
}
复制代码
RxJava2CallAdapterFactory的
get方法
//RxJava2CallAdapterFactory.java@Override public @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(returnType); if (rawType == Completable.class) { return new RxJava2CallAdapter(Void.class, scheduler, isAsync, false, true, false, false, false, true);
} boolean isFlowable = rawType == Flowable.class; //当前是Single类型
boolean isSingle = rawType == Single.class; boolean isMaybe = rawType == Maybe.class; if (rawType != Observable.class && !isFlowable && !isSingle && !isMaybe) { return null;
}
... //返回 RxJava2CallAdapter对象,isSingle参数为 true
return new RxJava2CallAdapter(responseType, scheduler, isAsync, isResult, isBody, isFlowable,
isSingle, isMaybe, false);
}
复制代码
返回的是 RxJava2CallAdapter 对象,并且根据 rawType 判断当前是个什么类型
看下 RxJava2CallAdapter 的
adapt方法
//RxJava2CallAdapter.java@Override public Object adapt(Call<R> call) { //1 把Call包装成一个Observable对象
Observable<Response<R>> responseObservable = isAsync
? new CallEnqueueObservable<>(call)
: new CallExecuteObservable<>(call);
Observable<?> observable; if (isResult) {
observable = new ResultObservable<>(responseObservable);
} else if (isBody) {
observable = new BodyObservable<>(responseObservable);
} else {
observable = responseObservable;
} if (scheduler != null) {
observable = observable.subscribeOn(scheduler);
} if (isFlowable) { return observable.toFlowable(BackpressureStrategy.LATEST);
} //2
if (isSingle) { return observable.singleOrError();
} if (isMaybe) { return observable.singleElement();
} if (isCompletable) { return observable.ignoreElements();
} return RxJavaPlugins.onAssembly(observable);
}
复制代码
注释 1:把 Call 包装成一个 Observable 对象
注释2:如果是 Single 则调用
observable.singleOrError();方法
到目前为止, CallAdapter 怎么变成一个 RxJava2CallAdapter 以及它的具体调用,我们也就清楚了。
整个流程中还有一点我们没有分析 Retrofit 如何支持 Kotlin 协程的 suspend 挂起函数的?
首先写一个 Demo 来看一下协程是怎么进行网络请求的
添加依赖
def kotlin_coroutines = '1.3.7'implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines"implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines"implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0'implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'复制代码
定义请求接口,写一个挂起函数
interface GitHubApiService { //使用 Kotlin 协程 ,定义一个挂起函数
@GET("users/{user}/repos") suspend fun listReposKt(@Path("user") user: String?): List<Repo>
}
复制代码
请求接口
//创建出GitHubApiService对象val service = retrofit.create(GitHubApiService::class.java)//lifecycle提供的协程的Scope,因为 suspend 函数需要运行在协程里面lifecycleScope.launchWhenResumed { try {
val repo = service.listReposKt("octocat") "response name = ${repo[0].name}".logE()
} catch (e: Exception) {
e.printStackTrace() //出错逻辑
//ignore
}
}
复制代码
以上就是一个,用 Kotlin 协程进行网络请求的,Retrofit 是支持 Kotlin 协程的,接下来看下,Retrofit 是怎么支持的。
首先在开始之前,我们得先得从代码角度知道,Kotlin 的 suspend 函数对应的 Java 类是什么样子,不然,就一个 suspend 关键字根本就没法进行分析。
我写一个 suspend 的测试方法,然后转换成 java 方法看一下,这个 suspend 函数是个啥。
写一个 Top Level 的Suspend.kt文件(在文章最后我会给出源码,一看就明白)
在文件中写了一个测试的 suspend 函数
suspend fun test(name: String) {
}
复制代码
我们通过 Android Studio 再带的工具,如下图:把 Kotlin 方法转成 Java 方法
点这个按钮
结果如下
public final class SuspendKt { @Nullable
public static final Object test(@NotNull String name, @NotNull Continuation $completion) { return Unit.INSTANCE;
}
}
复制代码
看到了,我们的 suspend 的关键字,变成了
test 方法的一个Continuation参数,且为最后一个参数
看一下这个 Continuation类, 记住这个类,下面在分析的时候会遇到
@SinceKotlin("1.3")public interface Continuation<in T> { public val context: CoroutineContext public fun resumeWith(result: Result<T>)}
复制代码
好目前的准备工作都已经完成,开始分析 Retrofit 是怎么支持 Kotlin 协程的挂起函数的。
经过前面的源码解读,我们知道,最终会调用到 HttpServiceMethod 的
parseAnnotations 方法
//HttpServiceMethod.javastatic <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) { //1 获取 isKotlinSuspendFunction 的值,这个会在下面具体分析
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction; boolean continuationWantsResponse = false; boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType; //2 如果是 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) {
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType); //3 continuationWantsResponse 赋值为 true
continuationWantsResponse = true;
} else {
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
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) { //4 返回 SuspendForResponse 它是 HttpServiceMethod的子类
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else { return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(
requestFactory,
callFactory,
responseConverter,
(CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
复制代码
注释 1:获取 isKotlinSuspendFunction 的值,这个会在下面具体分析
注释 2:如果是 Kotlin 挂起函数,进入此代码块
注释 3:把 continuationWantsResponse 赋值为 true
注释 4:返回 SuspendForResponse 它是 HttpServiceMethod 的子类,然后看它的
adapt方法,这个会在下面具体分析
获取 isKotlinSuspendFunction 的值的过程
requestFactory 这个类,我们之前分析过,就是解析注解的,但是有一部分没看,就是解析方法参数上的注解,这次就看下。
//RequestFactory.javaprivate @Nullable ParameterHandler<?> parseParameter( int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler<?> result = null; if (annotations != null) { for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = //1 遍历解析参数的注解,就是 @Path @Query @Field 等注解,具体就不看了,不是协程的重点
parseParameterAnnotation(p, parameterType, annotations, annotation); if (annotationAction == null) { continue;
} if (result != null) { throw parameterError(
method, p, "Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
} if (result == null) { //2 如果是协程 ,其实比的就是最后一个值
if (allowContinuation) { try { //3 判断参数类型是 Continuation,这个接口,前面在 10.2 小节写 Demo 时提过
if (Utils.getRawType(parameterType) == Continuation.class) { // 4 isKotlinSuspendFunction 赋值为 true
isKotlinSuspendFunction = true; return null;
}
} catch (NoClassDefFoundError ignored) {
}
} throw parameterError(method, p, "No Retrofit annotation found.");
} return result;
}
复制代码
注释 1:遍历解析参数的注解,就是 @Path @Query @Field 等注解,具体就不看了,不是协程的重点
注释 2:如果是协程 ,其实比的就是最后一个值
注释 3:判断参数类型是 Continuation,这个接口,前面在 10.2 小节写 Demo 时提过
注释 4:isKotlinSuspendFunction 赋值为 true
如果isKotlinSuspendFunction 为 true 时,返回就是 SuspendForResponse 类
接下来就要 SuspendForResponse 以及它的
adapt 方法了
static final class SuspendForResponse<ResponseT> extends HttpServiceMethod<ResponseT, Object> { private final CallAdapter<ResponseT, Call<ResponseT>> callAdapter;
SuspendForResponse(
RequestFactory requestFactory,
okhttp3.Call.Factory callFactory,
Converter<ResponseBody, ResponseT> responseConverter,
CallAdapter<ResponseT, Call<ResponseT>> callAdapter) { super(requestFactory, callFactory, responseConverter); this.callAdapter = callAdapter;
} @Override
protected Object adapt(Call<ResponseT> call, Object[] args) { //1
call = callAdapter.adapt(call); //noinspection unchecked Checked by reflection inside RequestFactory.
//2
Continuation<Response<ResponseT>> continuation =
(Continuation<Response<ResponseT>>) args[args.length - 1]; // See SuspendForBody for explanation about this try/catch.
try { //3
return KotlinExtensions.awaitResponse(call, continuation);
} catch (Exception e) { //4
return KotlinExtensions.suspendAndThrow(e, continuation);
}
}
}
复制代码
注释 1:调用 callAdapter 代理 call 方法
注释 2:取出最后一个参数,强转成 Continuation 类型,想想我们写的 Demo
注释 3:Call 的扩展函数(Kotlin 的写法)下面具体看下
awaitResponse
注释 4:出现异常,抛出异常。所以我们要在代码中,要主动 try catch,来处理错误
//KotlinExtensions.ktsuspend fun <T> Call<T>.awaitResponse(): Response<T> { return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
} //调用 Call的enqueue方法
enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { //成功回调
continuation.resume(response)
} override fun onFailure(call: Call<T>, t: Throwable) { //失败回调
continuation.resumeWithException(t)
}
})
}
}
复制代码
到现在,整个用 Kotlin 协程的请求过程我们也就看完了。
至此,整个 Retrofit 的整体流程就分析完了,具体细节还需要好好研究,我们再总结一下,回答开始的问题
分两点
动态指的是在运行期,而代理指的是实现了某个接口的具体类,称之为代理,会调用了 InvocationHandler 的
invoke方法。
Retrofit 中的动态代理:
listRepos方法时,会调用了 InvocationHandler 的
invoke方法。invoke方法。具体看第 6 节
listRepos方法时,会调用 InvocationHandler 的
invoke方法loadServiceMethod方法并返回一个 HttpServiceMethod 对象并调用它的
invoke方法enqueue方法enqueue方法以上就是这个Retrofit 的请求流程
看下第 11.2小节的解释吧
具体看第 8 节
具体看第 8.2 小节
parseResponse(rawResponse);方法开始convert 方法具体看第 8.4 小节
adapt方法具体看第 9 节
具体看第 10 节
到此为止,这篇文章算写完了,当然还有很多具体细节没有研究,但对 Retrofit 的各个方面都进行了阅读。
Android Retrofit源码解析 ——→
视频地址
作者:AboBack
链接:
https://juejin.cn/post/6869584323079569415
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69983917/viewspace-2803041/ ,如需转载,请注明出处,否则将追究法律责任。