全面解析 Retrofit 网络框架

作为 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)
    }
}
相关推荐
李慕婉学姐2 小时前
【开题答辩过程】以《基于uniapp的养宠互助服务程序设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
android·mysql·uni-app
移幻漂流2 小时前
JNI的本质解析:Android Framework视角下的Java-Native衔接机制
android·java·开发语言
浪客川2 小时前
1972 GODOT 入门案例
android·java·godot
粤M温同学3 小时前
Android Studio 有多个module,快速修改包名
android·android studio
学海无涯书山有路3 小时前
Android LiveData + MVVM 新手入门教程(基于 XML+Java)
android·xml·java
晚霞的不甘3 小时前
Flutter for OpenHarmony:注入灵魂:购物车的数据驱动与状态管理实战
android·前端·javascript·flutter·前端框架
福大大架构师每日一题3 小时前
milvus v2.6.9 发布:支持主键搜索、段重开机制、日志性能全面提升!
android·java·milvus
_李小白4 小时前
【Android 美颜相机】第十六天:GPUImageTwoInputFilter 解析
android·数码相机
wy3136228214 小时前
android——Android Studio 路径迁移指南(释放 C 盘空间)
android·ide·android studio