Retrofit 创建与配置过程
retrofit 简介
Retrofit 是一款基于 OkHttp 的强大网络请求库,专门用于简化 Android 和 Java 应用中的网络请求操作。它的设计理念是将 HTTP API 转换为 Java 接口,让开发者能够以更简洁、直观的方式与远程服务器进行通信,而无需直接处理底层的 HTTP 请求。
单 okhttp 的用法
private fun testOkhttp() {
val okHttpClient = OkHttpClient.Builder()
.readTimeout(5, TimeUnit.SECONDS)
.build()
val request = Request.Builder()
.url("https://system.xlxs.top/config/getCameraSyncNotice?language=zh_CN")
.get().build()
val call = okHttpClient.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
}
override fun onResponse(call: Call, response: Response) {
Log.i("TAG-jin", "onResponse: ${response.body?.string()}")
}
})
}
使用 retrofit 的用法
kotlin 协程方式
先定义 service 接口,方法定义为挂起函数、再定义 协程 scope
interface MineService {
// 定义一个挂起函数,用于获取相机同步通知
@GET("config/getCameraSyncNotice")
suspend fun getCameraSyncNotice(@Query("language") language: String): String
}
// 测试 Retrofit 的函数
private fun testRetrofit() {
// 创建 Retrofit 实例
val retrofit = Retrofit.Builder()
.baseUrl("https://xxx.test.top/")
.addConverterFactory(CustomGsonConverterFactory.create()) // 添加自定义的 Gson 转换器
.build()
// 创建 MineService 的实例
val mineService = retrofit.create(MineService::class.java)
// 使用 IO 线程发起网络请求,并在 Activity 生命周期内管理协程
IOLifecycleScope(this).launch {
try {
// 调用 MineService 的函数获取相机同步通知
val cameraSyncNotice = mineService.getCameraSyncNotice("")
println(cameraSyncNotice) // 打印相机同步通知
} catch (e: Exception) {
e.printStackTrace() // 打印异常信息
}
}
}
// 在 Activity 生命周期内管理 IO 协程的作用域
class IOLifecycleScope(private val activity: AppCompatActivity) : CoroutineScope {
private val job = SupervisorJob()
// 定义协程上下文,指定为 IO 线程,并绑定到 SupervisorJob
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
// 在 Activity 销毁时取消协程
init {
activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onDestroy(owner: LifecycleOwner) {
cancel() // 取消协程
}
})
}
}
传统方式
其中 Call 通过 CallAdapterFactory 来创建的,实例一般为 ExecutorCallbackCall
public interface ApiService {
@GET("user/{id}")
Call<User> getUser(@Path("id") int userId);
@POST("user/create")
Call<User> createUser(@Body User user);
// 其他方法定义...
}
// 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
// 创建接口实例
ApiService apiService = retrofit.create(ApiService.class);
// 发起请求
Call<User> call = apiService.getUser(1);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
// 处理响应结果
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// 处理请求失败
}
});
Retrofit 请求流程
动态代理生成接口的实现类基本流程
- 动态生成接口的实现类: 当调用
Retrofit.create()
方法时,Retrofit 将使用动态代理机制来生成接口的实现类。具体流程如下:- Retrofit 使用 Java 的
java.lang.reflect.Proxy
类创建一个动态代理对象,该代理对象实现了接口定义的所有方法。 - 在动态代理对象的方法调用中,会触发
InvocationHandler
的invoke()
方法,该方法被动态代理类实现,用于处理方法调用。 - Retrofit 的
Proxy
类会将方法调用委托给Retrofit
内部的ServiceMethod
对象来处理,该对象负责解析方法的注解信息,并构建对应的 HTTP 请求对象,返回 Call。
- Retrofit 使用 Java 的
注解如何转换成请求参数、生成Retrofit Call 过程
在使用过程中调用 service 实现类的方法就返回一个 Call,这里主要有两个步骤
loadServiceMethod(method)
调用接口定义的方法时会调用到 Retrofit#create 创建的 InvocationHandler 的 invoke 方法
会先调用 loadServiceMethod(method) 返回 ServiceMethod (HttpServiceMethod)。
这一步同时构建好 RequestFactory,该类会在 retrofit Call enqueue 时生成 okhttp Request,去构建 okhttp 的 Call
loadServiceMethod(method);
ServiceMethod.parseAnnotations(this, method);
RequestFactory.parseAnnotations(retrofit, method);
构建 RequestFactory
static RequestFactory parseAnnotations(Retrofit retrofit, Method method) {
return new Builder(retrofit, method).build();
}
RequestFactory build() {
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
……
}
最终调用到了 parseMethodAnnotation 方法
parseMethodAnnotation
用于解析接口方法上的注解信息,并根据不同的注解类型执行相应的处理逻辑。以下是对这个方法的总结:
- 首先判断注解的类型,根据不同的注解类型执行不同的处理逻辑。
- 对于 HTTP 请求方法的注解(
@GET
、@POST
、@PUT
、@DELETE
、@PATCH
、@HEAD
、@OPTIONS
和@HTTP
),调用parseHttpMethodAndPath
方法解析请求方法和请求路径,并根据注解中是否指定有请求体来确定是否需要包含请求体。 - 对于
@Headers
注解,解析其中的请求头信息,并存储到this.headers
字段中。 - 对于
@Multipart
和@FormUrlEncoded
注解,分别标识当前请求是否为多部分请求或表单编码请求,并进行相应的处理。
HttpServiceMethod 的 invoke
再调用 HttpServiceMethod 的 invoke 方法,通过适配器生成 具体的 Call
// HttpServiceMethod 的 invoke,这里先 new 一个 OkHttpCall,再通过适配器传入到最终 Call 里面,赋给 delegate 字段
@Override
final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
// CallAdapted 继承了 HttpServiceMethod,调用其 adapt 方法,ReturnT 为泛型,就是 Call
@Override
protected ReturnT adapt(Call<ResponseT> call, Object[] args) {
return callAdapter.adapt(call);
}
// 再调用 CallAdapter 的 adapt 方法返回一个 ExecutorCallbackCall
@Override
public Call<Object> adapt(Call<Object> call) {
return executor == null ? call : new ExecutorCallbackCall<>(executor, call);
}
Call enqueue 过程
在 Retrofit 中,Call
是 Retrofit 提供的一个抽象类, 实际上是通过 OkHttp 来执行这些网络请求的
当 Retrofit Call (ExecutorCallbackCall)的 enqueue()
方法被调用时,会调用 OkHttpCall
enqueue 方法,也就是Call 里面的 delegate 属性。并使用 OkHttp 的 callFactory.newCall()
方法创建一个 OkHttp 的 Call
对象,最终将请求转发给 OkHttp 进行执行
请求转换到 okhttp流程以及线程切换
流程图, okhttp 内部 enqueue 使用了线程池异步调用 ,不能更新UI 。故而 retrofit 接到响应再切主线程
Retrofit converter 转化原理
-
返回 stream (respondBody) 到 json (Bean)
GsonResponseBodyConverter
上一步 okhttp3.Callback() onResponse 时会调用 parseResponse 方法
会解析出来 body,也就是Call 封装的 泛型T,真正的响应内容
Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException { T body = responseConverter.convert(catchingBody); return Response.success(body, rawResponse); …… } // 这里的 responseConverter 就是配置时传进去的 convertor,把 okhttp 返回的 流转换成对象