Retrofit 环境搭建与 Gradle 依赖

本章从零搭建 Retrofit 网络层基础设施,涵盖 Gradle 依赖管理、HTTP 库选型、Retrofit 实例初始化及 Base URL 配置。最终得到一个可被注入的 Retrofit 单例,为后续接口分离与请求封装奠定基础。

1. 原理概述

Retrofit 本质是一个 声明式 HTTP 客户端,它通过 Java 注解 + 动态代理将接口方法转换为 OkHttp 请求。架构自上而下分为三层:

  • 应用层 — 开发者定义接口并用注解描述请求(GET、POST、Header、Path 等)。
  • Retrofit 核心 — 构建实例时绑定 Base URL、转换器(Converter)和 CallAdapter,运行时为接口生成代理实现。
  • 网络层 — 底层由 OkHttp 负责 TCP 连接、拦截器、缓存、连接池等能力。

下图展示了 Retrofit 初始化阶段的关键组件与协作路径:

Retrofit 初始化完整流程图 ① 项目级 build.gradle ② app 级 build.gradle ③ 添加依赖并 Gradle Sync ④ 创建 Retrofit.Builder ⑤ .baseUrl(“https://api.xxx.com/”) ⑥ .addConverterFactory(…) ⑦ .build() → Retrofit 单例 Base URL 必须符合 HTTP 规范,以 “/” 结尾;Converter 决定序列化格式(Gson / Moshi / Jackson)

2. 实现流程

  1. 定位 Gradle 文件 — 项目级 build.gradle.kts 或 build.gradle 用于定义插件版本,app 级文件用于声明依赖。
  2. 添加依赖 — 在 app 级 build.gradle.kts 的 dependencies 块中添加 Retrofit、OkHttp 及转换器库。
  3. 同步项目 — 执行 Gradle Sync,等待依赖下载完成。
  4. 编写 Retrofit 单例 — 使用 Retrofit.Builder 链式调用,设置 baseUrl 和 Converter。
  5. 验证配置 — 调用 create(Api::class.java) 并测试一个简单请求。

3. 代码实现

以下为基于 Kotlin DSL 的完整依赖配置与初始化代码。

app/build.gradle.kts — 核心依赖声明:

plugins {
    id("com.android.application")
    id("kotlin-android")
}

android {
    namespace = "com.example.retrofitdemo"
    compileSdk = 34
    defaultConfig {
        applicationId = "com.example.retrofitdemo"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }
}

dependencies {
    // Retrofit 核心
    implementation("com.squareup.retrofit2:retrofit:2.9.0")
    // OkHttp(Retrofit 自动依赖,可显式指定版本)
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
    // Gson 转换器(用于 JSON 序列化)
    implementation("com.squareup.retrofit2:converter-gson:2.9.0")
    // 日志拦截器(调试阶段使用)
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
}
兼容性提示:Retrofit 2.9.0 对应 Java 8+,若项目最低 API 低于 21 需启用 Java 8 脱糖。建议统一使用 converter-gson 进行 JSON 解析,Gson 版本会由 Retrofit 自动传递。

Retrofit 实例初始化 — 通常封装为单例,避免重复创建连接池:

object RetrofitClient {
    private const val BASE_URL = "https://api.example.com/"

    // 配置 OkHttpClient(添加日志拦截器用于调试)
    private val okHttpClient = OkHttpClient.Builder()
        .addInterceptor(HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY  // 生产环境建议设为 NONE
        })
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build()

    val retrofit: Retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)           // 绑定自定义 OkHttpClient
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}
Base URL 陷阱:baseUrl 必须以 “/” 结尾(如 https://api.xxx.com/),否则 Retrofit 在拼接注解中的相对路径时会抛出 IllegalArgumentException。同时 url 中不可包含空格或特殊字符。

4. 调试与验证

完成上述步骤后,可以编写一个临时的接口测试配置是否生效:

interface TestApi {
    @GET("health")
    suspend fun healthCheck(): Response<Map<String, Any>>
}

// 在 Activity/ViewModel 中调用
lifecycleScope.launch {
    val api = RetrofitClient.retrofit.create(TestApi::class.java)
    val response = api.healthCheck()
    if (response.isSuccessful) {
        Log.d("RetrofitTest", "Health OK: ${response.body()}")
    } else {
        Log.e("RetrofitTest", "Error: ${response.code()}")
    }
}

打开 Logcat 过滤 OkHttp 日志,若看到完整的请求/响应体,则说明网络层已打通。

5. 常见错误

错误现象原因解决方案
java.lang.IllegalArgumentException: baseUrl must end with /Base URL 不以 “/” 结尾检查并补上结尾斜杠
Unable to create call adapter for …未添加 CallAdapterFactory(如 RxJava)如需协程默认支持 Kotlin Coroutines,无需额外 adapter;若用 RxJava 需添加 adapter-rxjava3
java.lang.NoClassDefFoundError: okhttp3/OkHttpClient缺少 OkHttp 依赖在 dependencies 中添加 com.squareup.okhttp3:okhttp
Gradle 同步失败:Could not resolve com.squareup.retrofit2:retrofit:2.9.0网络或仓库未配置在项目级 settings.gradle.kts 中添加 mavenCentral()

6. 性能与稳定性优化

  • 单例化 Retrofit 实例:避免多次创建 OkHttpClient 导致连接池膨胀,使用 by lazy 或依赖注入容器。
  • 自定义 OkHttp 连接池:可根据业务设置最大空闲连接数与存活时间,减少 TCP 三次握手开销。
  • 调试日志等级:正式发布包中应将 HttpLoggingInterceptor.Level 设为 NONE 或 HEADERS,避免打印敏感数据且降低性能损耗。
  • Converter 选型:若项目已使用 Moshi / Kotlinx Serialization,优先选择对应的 Converter 以保持序列化一致性,减少对象拷贝次数。

示例:单例与 OkHttp 连接池优化

object NetworkProvider {
    val okHttpClient: OkHttpClient by lazy {
        OkHttpClient.Builder()
            .connectionPool(ConnectionPool(5, 5, TimeUnit.MINUTES))
            .build()
    }
    val retrofit: Retrofit by lazy {
        Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}