Android热门框架解析,你确定不来看看吗?
OkHttp框架源码深度剖析【Android热门框架分析第一弹】
Retrofit框架源码深度剖析【Android热门框架分析第二弹】
什么是Retrofit?
准确来说,Retrofit 是一个 RESTful 的 HTTP 网络请求框架的封装。
原因:网络请求的工作本质上是 OkHttp 完成,而 Retrofit 仅负责 网络请求接口的封装,当前最新的Retrofit底层使用的是OkHttp3。
上图说明了如下几点:
1. App应用程序通过 Retrofit 请求网络,实际上是使用 Retrofit 接口层封装请求参数、Header、Url 等信息,之 后由 OkHttp 完成后续的请求操作。
2. 在服务端返回数据之后,OkHttp 将原始的结果交给 Retrofit,Retrofit根据用户的需求对结果进行解析。
所以,网络请求的本质仍旧是OkHttp完成的,retrofit只是帮使用者来进行工作简化的,比如配置网络,处理数据等 工作,提高这一系列操作的复用性。这也就是网上流行的一个不太准确的总结:okhttp是瑞士军刀,retrofit则是将这把瑞士军刀包装成了一个非常好用的指甲钳(专治甲沟炎哈哈)。
为什么选择Retrofit?
我曾经写过一篇关于热门网络请求框架OkHttp的详细解析,但为什么我还要对Retrofit继续写文章呢?这肯定是因为Retrofit有它独特的优势。虽然OkHttp非常好用,但它也存在一些局限性。OkHttp最初的设计就是为了实现网络请求,而在实际应用中我们发现了一些缺点,这也促使了Retrofit的诞生。虽然Retrofit只是对OkHttp进行了封装,但它带来了很多显著的优点。
-
超级解耦:
Retrofit实现了接口定义、接口参数和接口回调的彻底解耦。这种设计不仅让代码更清晰、更易于维护,也使得代码的复用性大大提高。 -
灵活的HTTP客户端配置:
在Retrofit中,你可以轻松配置不同的HTTP客户端来实现网络请求,如OkHttp、HttpClient等。这种灵活性使得开发者可以根据项目需求选择最合适的HTTP客户端。 -
同步与异步支持:
Retrofit同时支持同步和异步请求,提供了更丰富的使用场景。此外,它还与RxJava无缝集成,方便进行响应式编程。 -
多种数据格式支持:
通过配置不同的反序列化工具类,Retrofit可以解析多种数据格式,如JSON、XML等。这样,开发者可以根据API的具体需求选择最适合的数据格式。 -
高效的请求速度:
由于Retrofit底层使用OkHttp,再加上其优秀的封装和优化,Retrofit在请求速度上表现优异。此外,它使用方便、灵活且简洁,极大地提高了开发效率。
就笔者自身使用而言,使用Retrofit会比使用OkHttp舒服的多,开发效率也会提升,okhttp需要手动解析数据,而Retrofit通过内置的转换器可以自动解析数据;同时,在网络请求时,Retrofit会自动帮你进行线程切换;除此之外,还使用动态代理的方式自动生成网络请求Api,当你在使用完OkHttp以后,再使用Retrofit,一定会让你欲罢不能的!
Retrofit对OkHttp做了什么?
Retrofit并没有改变网络请求的本质,也无需改变,因为Okhttp已经足够强大,Retrofit的封装可以说是很强大,里 面涉及到一堆的设计模式,可以通过注解直接配置请求,可以使用不同的http客户端,虽然默认是用http ,可以使用 不同Json Converter 来序列化数据,同时提供对RxJava的支持,使用Retrofit + OkHttp + RxJava 可以说是目前比较 潮的一套框架,但是需要有比较高的门槛。
OkHttp网络请求:
我们先来看看OkHttp是怎么进行网络请求的。
库的引入
implementation 'com.squareup.retrofit2:retrofit:2.11.0'
// 如果使用 Gson 进行 JSON 解析
implementation 'com.squareup.retrofit2:converter-gson:2.11.0'
如果你没有使用过OkHttp,可以看我之前的文章,在顶部有介绍;当然,你也直接看下面的OkHttp的简单使用。
// 1.创建client
val client = OkHttpClient.Builder()
.cookieJar(CookieJar.NO_COOKIES)
.callTimeout(10000, TimeUnit.MILLISECONDS)
.build()
// 2.创建request
val request = Request.Builder()
.url("http://10.34.12.156:68080/admin-api")
.addHeader("Content-Type", "application/json")
.get()
.build()
// 3.构建call对象
val call = client.newCall(request)
// 4.1调用call对象的同步请求方法
val response = call.execute() // response对象中保存的有返回的响应参数
4.2调用call对象的异步请求方法
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
Log.d("a", "onFailure:") // 失败回调
}
override fun onResponse(call: Call, response: Response) {
Log.d("b", "onResponse:") // 成功回调
}
})
Step1:创建HttpClient对象,也就是构建一个网络类型的实例,一般会将所有的网络请求使用同一个单例对象。
Step2:构建Request,也就是构建一个具体的网络请求对象,具体的请求url,请求头,请求体等等。
Step3:构建请求Call,也就是将具体的网络请求与执行请求的实体进行绑定,形成一个具体的正式的可执行实体。
Step4: 后面就进行网络请求了,然后处理网络请求的数据了。
是不是看着还挺容易的,一步步的,很好使用呢?
Okhttp给用户留下的问题:
1)用户网络请求的接口配置繁琐,尤其是需要配置请求body,请求头,参数的时候;
2)数据解析过程需要用户手动拿到responsbody进行解析,不能复用;
3)无法适配自动进行线程的切换。
那么这几个问题谁来解决? 对,retrofit!
Retrofit网络请求
1、创建 Retrofit 实例并配置:
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(baseUrl) // 指定根路径
.addConverterFactory(GsonConverterFactory.create()) // 指定解析数据时使用的转换库
.build()
2、创建服务接口实例:
val service: AppService = retrofit.create(AppService::class.java)
这个AppService就是定义的接口
3、发起网络请求:
val call: Call<ResponseBody> = service.getPostData(user, pwd)
ResponseBody是数据Bean,getPostData是接口定义的方法
call.enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>) {
if (response.isSuccessful) {
// 请求成功处理
Log.d("HttpUtil", "成功")
// 这里可以处理响应数据
} else {
// 请求失败处理
Log.e("HttpUtil", "请求失败")
}
}
override fun onFailure(call: Call<ResponseBody>?, t: Throwable) {
// 网络请求失败处理
t.printStackTrace()
Log.e("HttpUtil", "网络请求失败")
}
})
- step1
构建一个网络请求的载体对象,和okhttp构建OkhttpClient对象有一样的意义,只不过 retrofit在build的时候有非常多的初始化内容,这些内容可以为后面网络请求提供准备,如准备 现成转换Executor, Gson convert,RxJavaCallAdapter。
- step2(精髓)
使用 retrofit.create()
方法创建定义的服务接口 AppService
的实例。为统一配置网络请求完成动态代理的设置。
- step3
建具体网络请求对象Request(service),在这个阶段要完成的任务:
1)将接口中的注解翻译成对应的 参数;
2)确定网络请求接口的返回值response类型以及对应的转换器;
3)讲Okhttp的Request封装成为Retrofit的 OKhttpCall。
总结来说,就是根据请求service 的Interface来封装Okhttp请求Request。
通过下图,让我们来总结一下,retrofit是如何来封装okhttp请求的。(左图的Request都是OkHttp哈,写错了)
大体的网络流程是一致的,毕竟都是通过okhttp进行网络请求。主要的步骤都是:创建网络请求实体client->构建真 正的网络请求-> 将网络请求方案与真正的网络请求实体结合构成一个请求Call->执行网络请求->处理返回数据->处理 Android 平台的线程问题。
在上图中,我们看到的对比最大的区别是什么?
- 1)okhttp创建的是OkhttpClient,然而retrofit创建的是 Retrofit实例
- 2)构建蓝色的Requet的方案,retrofit是通过注解来进行的适配
- 3)配置Call的过程中,retrofit是利用Adapter适配的Okhttp 的Call
- 4)相对okhttp,retrofit会对responseBody进行 自动的Gson解析
- 5)相对okhttp,retrofit会自动的完成线程的切换。
那么retrofit是如何完成这几点的封装的呢?我们继续往下走,撸源码。
Retrofit追溯源码
我们从Retrofit构建这里开始入手,我们通过build拿到我们的retrofit对象,我们看看build干了什么。
public Retrofit build() {
// 1. 检查 baseUrl 是否为 null
if (this.baseUrl == null) {
throw new IllegalStateException("Base URL required.");
} else {
// 2. 检查 callFactory 是否为 null,如果是,则使用默认的 OkHttpClient
Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
// 3. 检查 callbackExecutor 是否为 null,如果是,则使用默认的 Platform.callbackExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = Platform.callbackExecutor;
}
// 4. 获取 BuiltInFactories 实例
BuiltInFactories builtInFactories = Platform.builtInFactories;
// 5. 创建 callAdapterFactories 列表并添加默认的 CallAdapter 工厂
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
List<? extends CallAdapter.Factory> defaultCallAdapterFactories = builtInFactories.createDefaultCallAdapterFactories(callbackExecutor);
callAdapterFactories.addAll(defaultCallAdapterFactories);
// 6. 创建 defaultConverterFactories 列表
List<? extends Converter.Factory> defaultConverterFactories = builtInFactories.createDefaultConverterFactories();
int defaultConverterFactoriesSize = defaultConverterFactories.size();
// 7. 创建 converterFactories 列表并添加默认的 Converter 工厂
List<Converter.Factory> converterFactories = new ArrayList<>(1 + this.converterFactories.size() + defaultConverterFactoriesSize);
converterFactories.add(new BuiltInConverters());
converterFactories.addAll(this.converterFactories);
converterFactories.addAll(defaultConverterFactories);
// 8. 创建并返回新的 Retrofit 实例
return new Retrofit(
callFactory,
this.baseUrl,
Collections.unmodifiableList(converterFactories),
defaultConverterFactoriesSize,
Collections.unmodifiableList(callAdapterFactories),
defaultCallAdapterFactories.size(),
callbackExecutor,
this.validateEagerly
);
}
}
抓重点:
// 2. 检查 callFactory 是否为 null,如果是,则使用默认的 OkHttpClient
Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Call.Factory
是 retrofit2.Call.Factory
接口的一个实例,它的主要目的是为每一个网络请求创建一个新的 Call
对象。也就是说,这里其实就是去取Call对象。这里实例化了OkHttpClient对象,我们继续往下看。
可以看到,这个类实现了Call.Factory这个接口,看到这里,有没有很熟悉?是不是和OkHttp一样的套路?(如果你没看过我写的一篇OkHttp的文章,你可以去看下)
public interface Call extends Cloneable {
/** Returns the original request that initiated this call. */
Request request();
Response execute() throws IOException;
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
Timeout timeout();
Call clone();
interface Factory {
Call newCall(Request request);
}
}
还记得OkHttp通过newCall方法构建的对象吗?有没有恍然大悟?原来和OkHttp是一样的,只是包装了一下而已。这里的Call.Factory
负责创建 Call
对象,而 Call
对象代表了一个可以执行的 HTTP 请求。通过 Call.Factory
,Retrofit
可以灵活地创建这些 Call
对象,支持不同的 HTTP 客户端实现。
总结:
OkHttpClient是 http 请求的载体包含socket等可以复用的对象,协议配置等等一切。 Request 创建的是一个具体的有url,header,等请求信息的一个网络请求,表示这个具体的请求。
Call 通往请求的,去执行请求的整个过程的一个抽象。也是进行网络请求的最终接口。
所以,此次调用,目的就是创建了一个OkHttpClient,换句话说,这里的调用就是生产 Okhttp网络请求需要的请求Call的,以备后面进行真正的网络请求。
接下来,我们看第三步
// 3. 检查 callbackExecutor 是否为 null,如果是,则使用默认的 Platform.callbackExecutor
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {//这里默认为空,所以我们只要不设置,这里都会自动取获取的
callbackExecutor = Platform.callbackExecutor;
}
我们先看,Executor是个什么玩意。非常简单,一个接口里面有一个抽象方法。
public interface Executor {
void execute(Runnable var1);
}
我们再去看Platform.callbackExecutor拿到了什么。
final class Platform {
@Nullable
static final Executor callbackExecutor;
static final Reflection reflection;
static final BuiltInFactories builtInFactories;
private Platform() {
}
static {
switch (System.getProperty("java.vm.name")) {
case "Dalvik":
callbackExecutor = new AndroidMainExecutor();
if (VERSION.SDK_INT >= 24) {
reflection = new Reflection.Android24();
builtInFactories = new BuiltInFactories.Java8();
} else {
reflection = new Reflection();
builtInFactories = new BuiltInFactories();
}
break;
......
}
}
}
可以看到,在android开发中,我们的 Platform.callbackExecutor会默认的拿到一个AndroidMainExecutor对象。我们再继续深入。
final class AndroidMainExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
AndroidMainExecutor() {
}
public void execute(Runnable r) {
this.handler.post(r);
}
}
可以看到,其实就是传入了一个AndroidMainExecutor对象,并且它持有主线程的looper,看到这里,你有没有想到为什么Retrofit可以自动完成线程切换呢?原因就在这里。其实,只要是android中的通信,基本都离不开handler的。 虽然这里已经把答案揭晓了,但是可能大家还是不理解,它是怎么实现线程切换的。
我们继续看,它到底是怎么完成线程切换的。
callbackExecutor = new AndroidMainExecutor(); if (VERSION.SDK_INT >= 24) { reflection = new Reflection.Android24(); builtInFactories = new BuiltInFactories.Java8();还记得这行代码吗? } else { reflection = new Reflection(); builtInFactories = new BuiltInFactories();还记得这行代码吗? }
我们通过new BuiltInFactories()获得了这个BuiltInFactories这个对象。
class BuiltInFactories {
BuiltInFactories() {
}
List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
return Collections.singletonList(new DefaultCallAdapterFactory(callbackExecutor));
}
List<? extends Converter.Factory> createDefaultConverterFactories() {
return Collections.emptyList();
}
@TargetApi(24)
static final class Java8 extends BuiltInFactories {
Java8() {
}
List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
return Arrays.asList(new CompletableFutureCallAdapterFactory(), new DefaultCallAdapterFactory(callbackExecutor));
}
List<? extends Converter.Factory> createDefaultConverterFactories() {
return Collections.singletonList(new OptionalConverterFactory());
}
}
}
BuiltInFactories builtInFactories = Platform.builtInFactories;在这里我们拿到了我们的builtInFactories的实例对象。
在第5步是,我们构建工厂的时候,用到了builtInFactories
// 5. 创建 callAdapterFactories 列表并添加默认的 CallAdapter 工厂
List<CallAdapter.Factory> callAdapterFactories = new ArrayList<>(this.callAdapterFactories);
List<? extends CallAdapter.Factory> defaultCallAdapterFactories = builtInFactories.createDefaultCallAdapterFactories(callbackExecutor);
callAdapterFactories.addAll(defaultCallAdapterFactories);
调用builtInFactories.createDefaultCallAdapterFactories(callbackExecutor),这里传入了我们在第3步拿到的callbackExecutor,继续看createDefaultCallAdapterFactories这个方法做了什么。
List<? extends CallAdapter.Factory> createDefaultCallAdapterFactories(@Nullable Executor callbackExecutor) {
return Collections.singletonList(new DefaultCallAdapterFactory(callbackExecutor));
}
这里return Collections.singletonList(new DefaultCallAdapterFactory(callbackExecutor));我们继续看 DefaultCallAdapterFactory。
DefaultCallAdapterFactory有个静态内部类。这里通过构造方法,传入我们的Executor对象和我们的Call。当我们调用enqueue方法时,其实就是调用我们call对象的exqueue方法,在exqueue方法中又将我们的onResponse和onFailure通过Executor的execute包起来,从而实现Retrofit的自动切换线程的功能。(看到这,可能你有点懵,你现在要知道一个点,它其实就是通过Executor将请求结果的响应包装起来,发送给主线程。现在你可能无法将知识串起来,先记住,继续往下看)
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate;
ExecutorCallbackCall(Executor callbackExecutor, Call<T> delegate) {
this.callbackExecutor = callbackExecutor;
this.delegate = delegate;
}
public void enqueue(final Callback<T> callback) {
Objects.requireNonNull(callback, "callback == null");
this.delegate.enqueue(new Callback<T>() {
public void onResponse(Call<T> call, Response<T> response) {
ExecutorCallbackCall.this.callbackExecutor.execute(() -> {
if (ExecutorCallbackCall.this.delegate.isCanceled()) {
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);
});
}
});
}
.......
}
然后其他的话,我们还看到很多factory,这些factory的话基本上是给我们解析数据等其他作用的,这里暂不深入。
现在,我们已经构建好了Retrofit,这些步骤用于进行后面请求的需要的内容的一个准备工作。也就是封装Okhttp需要的准备工作。
我们继续往下看,下面两行代码需要连起来才能正确的被阅读,因为,在create里面是使用了动态代理的技术方案,而动态代理是运行时生效的。AppService就是一个接口(相当于Api)里面有很多抽象方法就相当于不同的请求。
2、创建服务接口实例: val service: AppService = retrofit.create(AppService::class.java) 这个AppService就是定义的接口 3、发起网络请求: val call: Call<ResponseBody> = service.getPostData(user, pwd) ResponseBody是数据Bean,getPostData是接口定义的方法
这里我们继续看create的代码。
public <T> T create(final Class<T> service) {
// 验证服务接口是否合法
this.validateServiceInterface(service);
// 创建代理实例
return Proxy.newProxyInstance(
service.getClassLoader(), // 获取服务接口的类加载器
new Class[]{service}, // 代理的接口列表,这里只有一个接口
new InvocationHandler() { // 代理调用处理器
private final Object[] emptyArgs = new Object[0]; // 空参数数组,用于没有参数的方法
@Nullable
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
// 如果是Object类的方法,直接调用
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
} else {
// 如果参数为空,则使用空参数数组
args = args != null ? args : this.emptyArgs;
// 获取平台特定的反射实例
Reflection reflection = Platform.reflection;
// 如果是默认方法,通过反射调用默认方法
return reflection.isDefaultMethod(method)
? reflection.invokeDefaultMethod(method, service, proxy, args)
// 否则,通过Retrofit加载服务方法,并调用它
: Retrofit.this.loadServiceMethod(service, method).invoke(proxy, args);
}
}
}
);
}
这里我们先将一下什么是动态代理。
在动态代理中,代理对象不需要实现接口,但是目标对象还是需要实现接口。代理对象的生成,是利用 JDK 的 API ,动态的在内存中构建代理对象。
在 Java 中,java.lang.reflect.Proxy
类为对象生成代理提供了方法:
Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler())
- 参数一 service.getClassLoader():返回的是
service
接口的类加载器,用于加载这个接口及其方法。 - 参数二 new Class[]{service}:指定这个代理类能够代理目标对象的哪些方法和接口;它包含了所有需要被代理的方法的声明
- 参数三
InvocationHandler
:用来指定生成的代理对象在方法被调用时如何进行处理;
所以,service
参数本身并不包含实际的方法实现,它只是一个接口的类对象,定义了方法的签名(方法名、参数类型、返回类型等)。当你调用这些方法时,实际上会进入 InvocationHandler
的 invoke
方法中,通过反射等机制来实现对这些方法的具体处理,从而实现代理模式。
因此,service
在这里不包含具体方法的实现,而是作为动态代理的基础接口,通过动态代理技术来生成实际的代理对象,以便在运行时动态处理方法调用。
说完动态代理,我们继续看代码。
// 验证服务接口是否合法
this.validateServiceInterface(service);
我将validateServiceInterface方法分为两部分。
private void validateServiceInterface(Class<?> service) {
第一部分
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
} else {
Deque<Class<?>> check = new ArrayDeque(1);
check.add(service);
while(!check.isEmpty()) {
Class<?> candidate = (Class)check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message = (new StringBuilder("Type parameters are unsupported on ")).append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
Collections.addAll(check, candidate.getInterfaces());
}
第二部分
if (this.validateEagerly) {
Reflection reflection = Platform.reflection;
Method[] var9 = service.getDeclaredMethods();
int var5 = var9.length;
for(int var6 = 0; var6 < var5; ++var6) {
Method method = var9[var6];
if (!reflection.isDefaultMethod(method) && !Modifier.isStatic(method.getModifiers()) && !method.isSynthetic()) {
this.loadServiceMethod(service, method);
}
}
}
}
}
第一部分,主要做的是检查我们的service是否是接口。如果不是接口,我们将继续检查它是否是泛型接口,如果定义了则抛出异常。这是因为,Retrofit 在创建服务接口代理对象之前检查是否是泛型接口,是为了确保动态代理能够正确地工作。只有非泛型的接口才能确保在运行时通过动态代理生成有效的代理对象,并且能够正确地调用接口方法,实现网络请求和响应的处理。
我们再看第二部分,第二部分其实是去进行实际的方法加载和验证,对我们写好的网络请求进行验证。这里默认为false,从而实现Retrofit在创建服务接口实例时不会急切地验证接口方法。相反,它仅在实际调用方法时进行验证。
这里我们分析一下它是如何验证的。这里将我们获得到的所有的方法进行遍历,然后调用下面这个方法进行验证。
this.loadServiceMethod(service, method);
我们继续看loadServiceMethod方法。
// 加载服务方法,并将其缓存起来
// 参数:
// service: 要加载方法的服务接口类
// method: 要加载的方法
ServiceMethod<?> loadServiceMethod(Class<?> service, Method method) {
while(true) {
// 从缓存中查找对应方法的 ServiceMethod 对象
Object lookup = this.serviceMethodCache.get(method);
if (lookup instanceof ServiceMethod) {
// 如果缓存中已经有了该方法的 ServiceMethod 对象,则直接返回
return (ServiceMethod) lookup;
}
if (lookup == null) {
// 如果缓存中没有该方法的 ServiceMethod 对象,则加锁尝试创建
Object lock = new Object();
synchronized (lock) {
// 双重检查,确保只有一个线程创建 ServiceMethod 对象
lookup = this.serviceMethodCache.putIfAbsent(method, lock);
if (lookup == null) {
// 创建 ServiceMethod 对象并放入缓存
ServiceMethod result;
try {
result = ServiceMethod.parseAnnotations(this, service, method);
} catch (Throwable var10) {
// 如果创建过程中出现异常,则移除缓存并抛出异常
this.serviceMethodCache.remove(method);
throw var10;
}
this.serviceMethodCache.put(method, result);
return result;
}
}
}
// 如果有其他线程正在创建 ServiceMethod 对象,则等待该线程完成并获取结果
synchronized (lookup) {
Object result = this.serviceMethodCache.get(method);
if (result != null) {
return (ServiceMethod) result;
}
}
}
}
这里注释里面写的很清楚了。用缓存提高效率,没有缓存则加锁创建,这里使用的是双重检查。不过目前,我们还是没有看见它是怎么验证我们的方法的正确性的,所以我们需要继续往下看。
result = ServiceMethod.parseAnnotations(this, service, method);
这里就是我们验证的关键,调用parseAnnotations
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Class<?> service, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, service, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw Utils.methodError(method, "Method return type must not include a type variable or wildcard: %s", new Object[]{returnType});
} else if (returnType == Void.TYPE) {
throw Utils.methodError(method, "Service methods cannot return void.", new Object[0]);
} else {
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
}
我们从parseAnnotations一路分析下去,我们将会看到以下代码:
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
this.parseHttpMethodAndPath("DELETE", ((DELETE)annotation).value(), false);
} else if (annotation instanceof GET) {
this.parseHttpMethodAndPath("GET", ((GET)annotation).value(), false);
} else if (annotation instanceof HEAD) {
this.parseHttpMethodAndPath("HEAD", ((HEAD)annotation).value(), false);
} else if (annotation instanceof PATCH) {
this.parseHttpMethodAndPath("PATCH", ((PATCH)annotation).value(), true);
} else if (annotation instanceof POST) {
this.parseHttpMethodAndPath("POST", ((POST)annotation).value(), true);
} else if (annotation instanceof PUT) {
this.parseHttpMethodAndPath("PUT", ((PUT)annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
this.parseHttpMethodAndPath("OPTIONS", ((OPTIONS)annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP)annotation;
this.parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
retrofit2.http.Headers headers = (retrofit2.http.Headers)annotation;
String[] headersToParse = headers.value();
if (headersToParse.length == 0) {
throw Utils.methodError(this.method, "@Headers annotation is empty.", new Object[0]);
}
this.headers = this.parseHeaders(headersToParse, headers.allowUnsafeNonAsciiValues());
} else if (annotation instanceof Multipart) {
if (this.isFormEncoded) {
throw Utils.methodError(this.method, "Only one encoding annotation is allowed.", new Object[0]);
}
this.isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (this.isMultipart) {
throw Utils.methodError(this.method, "Only one encoding annotation is allowed.", new Object[0]);
}
this.isFormEncoded = true;
}
}
这里对我们写好的方法进行验证。 那么方法正确难道方法就一定可行吗?所以,Retrofit还对我们的请求结果进行验证了。
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
通过这行代码实现,代码里面注释写的很详细。
// 解析方法的注解和参数,生成对应的 HttpServiceMethod 对象
// 参数:
// retrofit: Retrofit 实例,用于创建适配器和转换器
// method: 当前要解析的方法
// requestFactory: 请求工厂,包含请求方法和参数信息
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 是否为 Kotlin 的挂起函数
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
// 是否挂起函数需要返回响应对象
boolean continuationWantsResponse = false;
// 挂起函数返回体是否可为 null
boolean continuationBodyNullable = false;
// 挂起函数返回类型是否为 Unit
boolean continuationIsUnit = false;
// 获取方法的所有注解
Annotation[] annotations = method.getAnnotations();
Object adapterType;
Type responseType;
// 如果是 Kotlin 挂起函数
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
// 获取返回类型的实际泛型参数
responseType = Utils.getParameterLowerBound(0, (ParameterizedType) parameterTypes[parameterTypes.length - 1]);
// 如果返回类型是 Response 类型且包含泛型参数
if (Utils.getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// 如果返回类型是 retrofit2.Call 类型,则抛出异常
if (Utils.getRawType(responseType) == retrofit2.Call.class) {
throw Utils.methodError(method, "Suspend functions should not return Call, as they already execute asynchronously.\nChange its return type to %s", new Object[]{Utils.getParameterUpperBound(0, (ParameterizedType) responseType)});
}
// 判断返回类型是否为 Unit
continuationIsUnit = Utils.isUnit(responseType);
}
// 创建一个参数化类型的 Call 类型
adapterType = new Utils.ParameterizedTypeImpl((Type) null, retrofit2.Call.class, new Type[]{responseType});
// 确保 SkipCallbackExecutorImpl 存在
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
// 非 Kotlin 挂起函数,获取方法的返回类型
adapterType = method.getGenericReturnType();
}
// 创建调用适配器
CallAdapter<ResponseT, ReturnT> callAdapter = createCallAdapter(retrofit, method, (Type) adapterType, annotations);
// 获取适配器的响应类型
responseType = callAdapter.responseType();
// 校验返回类型是否合法
if (responseType == okhttp3.Response.class) {
throw Utils.methodError(method, "'" + Utils.getRawType(responseType).getName() + "' is not a valid response body type. Did you mean ResponseBody?", new Object[0]);
} else if (responseType == Response.class) {
throw Utils.methodError(method, "Response must include generic type (e.g., Response<String>)", new Object[0]);
} else if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType) && !Utils.isUnit(responseType)) {
throw Utils.methodError(method, "HEAD method must use Void or Unit as response type.", new Object[0]);
} else {
// 创建响应体转换器
Converter<ResponseBody, ResponseT> responseConverter = createResponseConverter(retrofit, method, responseType);
// 获取 Retrofit 的调用工厂
Call.Factory callFactory = retrofit.callFactory;
// 如果不是 Kotlin 挂起函数,返回 CallAdapted 对象
if (!isKotlinSuspendFunction) {
return new CallAdapted(requestFactory, callFactory, responseConverter, callAdapter);
} else {
// 如果是 Kotlin 挂起函数,根据需要返回 Response 或 Body 的挂起函数对象
return (HttpServiceMethod<ResponseT, ReturnT>) (continuationWantsResponse ?
new SuspendForResponse<>(requestFactory, callFactory, responseConverter, callAdapter) :
new SuspendForBody<>(requestFactory, callFactory, responseConverter, callAdapter, continuationBodyNullable, continuationIsUnit));
}
}
}
好的,我们所有的准备工作以及相关的原理解析,我们都已经说明白了。那么当我们调用方法的时候,是怎么实现这一切的呢?是怎么串起来的呢?
3、发起网络请求:
val call: Call<ResponseBody> = service.getPostData(user, pwd)
ResponseBody是数据Bean,getPostData是接口定义的方法
call.enqueue(object : Callback<ResponseBody> {
override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>) {
if (response.isSuccessful) {
// 请求成功处理
Log.d("HttpUtil", "成功")
// 这里可以处理响应数据
} else {
// 请求失败处理
Log.e("HttpUtil", "请求失败")
}
}
override fun onFailure(call: Call<ResponseBody>?, t: Throwable) {
// 网络请求失败处理
t.printStackTrace()
Log.e("HttpUtil", "网络请求失败")
}
})
这里我们调用getPostData方法进行网络请求,结合retrofit的动态代理,我们将会执行下面的invoke方法。
public Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
} else {
args = args != null ? args : this.emptyArgs;
Reflection reflection = Platform.reflection;
return reflection.isDefaultMethod(method) ? reflection.invokeDefaultMethod(method, service, proxy, args) : Retrofit.this.loadServiceMethod(service, method).invoke(proxy, args);
}
}
注意看,Retrofit.this.loadServiceMethod(service, method).invoke(proxy, args);
当我们通过loadServiceMethod拿到我们的方法的时候,又调用了invoke函数。这里其实就是发起网络请求以后,通过invoke结合适配器的adapt方法将我们的数据直接转为我们的Bean。(或者结合RxJava使用)
我们看看HttpServiceMethod.adapt()方法:(其实是ServiceMethod的只不过HttpServiceMethod实现了ServiceMethod)。这里其实就是适配器的工作,你需要什么类型的数据就通过适配器适配,返回适配后的对象就是了。
final ReturnT invoke(Object instance, Object[] args) {
retrofit2.Call<ResponseT> call = new OkHttpCall(this.requestFactory, instance, args, this.callFactory, this.responseConverter);
return this.adapt(call, args);
}
总结
一般的Retrofit网络请求的操作是指 Call.excute() & Call.enqueue()的过程,这个过程才是真正的网络请求,因为,网络配置、请求地址配置、Call适配、网络请求requestBody、返回值responseBody转化适配准备工作都已经完成。
在进行网络请求的执行的时候,基本上就是调用,ServiceMethod中设置的各个内容
1)OkHttpCall进行网络请求,实则是进行okhttp的网络请求;
2)利用 converter进行网络请求数据的转换,一般是Gson();
3)利用 rxjava observable构建 rxjava类型的责任链访问方案,并进行线程切换;
4) 如果没有rxjava的添加,那么就使用默认的callAdapter里面的callbackExecutor进行线程的切换 , 进行网络请求.
学生记录所做,如有错误,欢迎指出。