作为 Android 开发中最主流的网络请求框架之一,Retrofit 几乎是每个中高级 Android 开发者的必备技能。如果你已经了解 OkHttp(底层核心),那么 Retrofit 就是站在 OkHttp 肩膀上的 "上层优雅封装"------ 它解决了 OkHttp 原生使用繁琐、缺乏类型安全、数据解析冗余等问题,让网络请求开发变得简洁、可维护。
一、Retrofit 是什么?
Retrofit 是由 Square 公司(OkHttp 同一家)开发的类型安全的 HTTP 客户端,本质是对 OkHttp 的封装,核心思想是 "将 HTTP API 转化为 Java/Kotlin 接口",通过注解 + 动态代理的方式,让开发者以 "面向接口编程" 的形式发起网络请求。
Retrofit 和 OkHttp 的关系
OkHttp 负责底层网络请求实现,负责 TCP 连接、请求发送 / 响应接收、连接池、拦截器等核心网络能力,是功能的真正实现者。Retrofit 是对 OkHttp 的一层封装,不直接处理网络请求,而是将开发者定义的接口转化成 OkHttp 能识别的请求对象,解决的是开发体验问题。
二、Retrofit 的基本使用
以"获取用户信息"的GET请求为例
添加依赖
XML
// Retrofit核心库
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
// Gson转换器(解析JSON,必加)
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
// 可选:RxJava3适配器(如果用RxJava处理异步)
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
// 可选:协程适配器(Kotlin推荐)
implementation 'com.squareup.retrofit2:adapter-coroutines:2.9.0'
定义数据模型
Kotlin
// User.kt
data class User(
val id: Int,
val name: String,
val age: Int
)
定义 Retrofit 接口
Kotlin
// UserApi.kt
interface UserApi {
// GET请求,{id}是路径参数,@Path替换路径中的占位符
@GET("user/{id}")
fun getUserById(
@Path("id") userId: Int, // 路径参数
@Query("token") token: String // 查询参数(拼接在URL后)
): Call<User> // Call<T>是Retrofit的请求封装,T是响应数据类型
}
创建 Retrofit 实例(单例)
Kotlin
// RetrofitClient.kt
object RetrofitClient {
private const val BASE_URL = "https://api.example.com/"
// 全局单例Retrofit
val retrofit: Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL) // 基础URL(必须以/结尾)
.client(OkHttpClient.Builder() // 自定义OkHttp客户端(可选)
.connectTimeout(10, TimeUnit.SECONDS) // 连接超时
.readTimeout(10, TimeUnit.SECONDS) // 读取超时
.build()
)
.addConverterFactory(GsonConverterFactory.create()) // Gson解析器
.build()
}
// 获取Api接口的代理对象
val userApi: UserApi by lazy {
retrofit.create(UserApi::class.java)
}
}
异步请求
Kotlin
// 在Activity/Fragment中调用
val call = RetrofitClient.userApi.getUserById(1001, "abc123")
call.enqueue(object : Callback<User> {
// 请求成功(响应码2xx)
override fun onResponse(call: Call<User>, response: Response<User>) {
if (response.isSuccessful) {
val user = response.body() // 获取解析后的User对象
// 注意:回调在子线程,更新UI需切主线程
runOnUiThread {
tvName.text = user?.name
}
} else {
// 响应失败(如404、500)
Log.e("UserApi", "请求失败:${response.code()}")
}
}
// 请求失败(如网络错误、超时)
override fun onFailure(call: Call<User>, t: Throwable) {
Log.e("UserApi", "请求异常:${t.message}")
}
})
同步请求(仅在子线程使用,不推荐)
Kotlin
// 必须在子线程(如Coroutine、Thread)中执行
thread {
try {
val call = RetrofitClient.userApi.getUserById(1001, "abc123")
val response = call.execute() // 同步执行,阻塞线程
if (response.isSuccessful) {
val user = response.body()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
三、Retrofit 核心角色与作用
Retrofit 的核心设计是 "组件化",每个角色各司其职,保证框架的扩展性和灵活性。以下是核心组件的作用:
|---------------|------------------------------------------------------------------------|
| 组件/类 | 核心作用 |
| Retrofit | 全局入口,通过构建器配置 BaseUrl、OkHttpClient、Converter、CallAdapter等;负责创建接口的动态代理对象 |
| ServiceMethod | 核心解析类,解析接口方法上的注解(@GET/@POST 等),封装请求 URL、参数、请求体等信息 |
| Call<T> | 请求封装接口,代表一次 HTTP 请求;默认实现是OkHttpCall,桥接 Retrofit 和 OkHttp |
| OkHttpCall | Call<T>的默认实现,内部持有 OkHttp 的okhttp3.Call,实际发起网络请求 |
| Converter | 数据转换器,处理请求体序列化(如 JSON→RequestBody)和响应体反序列化(如 ResponseBody→User) |
| CallAdapter | 调用适配器,将Call<T>转换为其他类型(如 RxJava 的Observable<T>、协程的Deferred<T>) |
| 动态代理(Proxy) | Retrofit 的核心机制,为接口生成代理对象,拦截接口方法调用,转化为 HTTP 请求 |
四、Retrofit 底层原理解析
你可能会疑惑:为什么定义的UserApi接口没有实现类,却能直接调用方法?
答案是动态代理:当调用retrofit.create(UserApi::class.java)时,Retrofit 会为UserApi生成一个动态代理对象。当你调用getUserById()时,实际执行的是代理对象的invoke()方法。
完整请求执行流程如下:
- 接口方法调用:开发者调用代理对象的接口方法(如
getUserById); - 注解解析:
ServiceMethod解析方法上的@GET、@Path等注解,拼接完整 URL、处理参数,生成Request对象(OkHttp 的请求对象); - 创建 OkHttpCall:将
Request封装为OkHttpCall,内部创建 OkHttp 的okhttp3.Call; - 发起请求:调用
enqueue()(异步)或execute()(同步),由 OkHttp 实际处理网络请求; - 响应解析:请求完成后,
Converter将 OkHttp 的ResponseBody转换为开发者定义的User对象; - 回调返回:将解析后的结果通过
Callback返回给开发者。
Retrofit 的灵活性在于 Converter 和 CallAdapter 这两个组件的扩展能力
- Converter:默认支持 Gson、Jackson、Protobuf 等,也可自定义(比如解析 XML);
- CallAdapter:默认返回
Call<T>,可扩展为 RxJava 的Observable<T>、协程的Flow<T>,适配不同的异步编程模型。
示例:自定义 Converter(解析 XML)
Kotlin
// 自定义XML转换器工厂
class XmlConverterFactory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *>? {
// 实现XML→Java对象的解析逻辑
return Converter<ResponseBody, Any> { value ->
val xmlString = value.string()
// 解析XML为目标对象
XmlParser.parse(xmlString, type)
}
}
companion object {
fun create(): XmlConverterFactory = XmlConverterFactory()
}
}
// 添加到Retrofit构建器
Retrofit.Builder()
.addConverterFactory(XmlConverterFactory.create())
.build()
五、Retrofit 的核心优势
到这里,我们就了解到了 Retrofit 的一些优势:
- 类型安全:编译期检查错误(比如参数类型不匹配、URL 拼写错误),避免运行时崩溃;
- 面向接口编程:将网络请求抽象为接口,解耦请求定义与实现,便于测试和维护;
- 高度可扩展:通过 Converter 和 CallAdapter 适配任意数据格式和异步模型;
- 无缝复用 OkHttp 能力:直接继承 OkHttp 的连接池、拦截器、超时配置、HTTPS 等核心特性;
- 简洁易用:一行注解搞定 URL、参数、请求方法,无需手动拼接 URL 和解析数据;
- 适配主流异步方案:支持原生回调、RxJava、协程,适配 Android 不同的开发模式。
Retrofit 还可以搭配协程、Hilt 等搭配写出更优雅的代码
Kotlin
// 使用协程替代回调
// 1. 定义接口(返回Deferred或suspend函数)
interface UserApi {
@GET("user/{id}")
suspend fun getUserById(
@Path("id") userId: Int,
@Query("token") token: String
): User // suspend函数直接返回数据,无需Call<T>
}
// 2. 调用(在协程作用域中)
lifecycleScope.launch {
try {
val user = RetrofitClient.userApi.getUserById(1001, "abc123")
tvName.text = user.name
} catch (e: Exception) {
Log.e("UserApi", "请求失败:${e.message}")
}
}
// Hilt统一管理Retrofit实例和网络接口
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
// 提供全局OkHttpClient依赖注入实例
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(BadRequestInterceptor())
.connectTimeout(NetworkConstants.CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(NetworkConstants.READ_TIMEOUT, TimeUnit.SECONDS)
.build()
}
@Provides
@Singleton
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(NetworkConstants.BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
@Provides
@Singleton
fun provideSocialApi(retrofit: Retrofit): UserApi {
return retrofit.create(UserApi::class.java)
}
}