OkHttp 与 Retrofit 完美结合:打造高效的 Android 网络请求

发布于:2025-07-22 ⋅ 阅读:(17) ⋅ 点赞:(0)

前言

在现代 Android 开发中,网络请求是几乎每个应用都必不可少的功能。OkHttp 和 Retrofit 作为当前最流行的网络请求库组合,为开发者提供了简洁高效的解决方案。本文将详细介绍如何将这两者结合使用,充分发挥它们的优势。

一、OkHttp 和 Retrofit 简介

1. OkHttp

OkHttp 是一个高效的 HTTP 客户端,具有以下特点:

  • 支持 HTTP/2,允许所有请求共享同一个 socket

  • 连接池减少请求延迟

  • 透明的 GZIP 压缩

  • 响应缓存避免重复网络请求

  • 自动处理网络问题,支持请求重试

2. Retrofit

Retrofit 是一个基于 OkHttp 的 RESTful HTTP 网络请求框架,它:

  • 通过接口和注解配置网络请求

  • 支持多种数据解析方式(Gson、Jackson、Moshi 等)

  • 支持 RxJava 和 Coroutines

  • 将 HTTP API 转换为 Java/Kotlin 接口

二、基本集成与使用

1. 添加依赖

首先在 build.gradle 中添加依赖:

implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // Gson 转换器

2. 创建 Retrofit 实例

val okHttpClient = OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(30, TimeUnit.SECONDS)
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

3. 定义 API 接口

interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") userId: String): User
    
    @POST("users")
    suspend fun createUser(@Body user: User): Response<Unit>
    
    @GET("users")
    suspend fun getUsers(@Query("page") page: Int): List<User>
}

4. 发起网络请求

val apiService = retrofit.create(ApiService::class.java)

// 使用协程
lifecycleScope.launch {
    try {
        val user = apiService.getUser("123")
        // 处理 user 数据
    } catch (e: Exception) {
        // 处理异常
    }
}

三、高级功能与配置

1. 添加公共请求头和参数

通过 OkHttp 的拦截器实现:

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val originalRequest = chain.request()
        val requestWithHeaders = originalRequest.newBuilder()
            .header("Authorization", "Bearer token")
            .header("Accept", "application/json")
            .method(originalRequest.method, originalRequest.body)
            .build()
        chain.proceed(requestWithHeaders)
    }
    .addInterceptor(HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    })
    .build()

2. 缓存配置

val cacheSize = 10 * 1024 * 1024 // 10 MB
val cache = Cache(File(context.cacheDir, "httpCache"), cacheSize.toLong())

val okHttpClient = OkHttpClient.Builder()
    .cache(cache)
    .addInterceptor { chain ->
        val request = chain.request()
        val response = chain.proceed(request)
        
        val cacheControl = CacheControl.Builder()
            .maxAge(1, TimeUnit.HOURS)
            .build()
            
        response.newBuilder()
            .header("Cache-Control", cacheControl.toString())
            .build()
    }
    .build()

3. 文件上传与下载

文件上传:

@Multipart
@POST("upload")
suspend fun uploadFile(
    @Part file: MultipartBody.Part,
    @Part("description") description: RequestBody
): Response<UploadResponse>

// 使用示例
val file = File(filePath)
val requestFile = RequestBody.create("image/*".toMediaTypeOrNull(), file)
val part = MultipartBody.Part.createFormData("file", file.name, requestFile)
val description = "This is a test file".toRequestBody()

apiService.uploadFile(part, description)

文件下载:

@Streaming
@GET
suspend fun downloadFile(@Url fileUrl: String): Response<ResponseBody>

// 使用示例
val response = apiService.downloadFile("https://example.com/file.zip")
if (response.isSuccessful) {
    val inputStream = response.body()?.byteStream()
    // 保存文件
}

4. 错误统一处理

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val request = chain.request()
        val response = chain.proceed(request)
        
        when (response.code) {
            401 -> {
                // 处理未授权
                throw UnauthorizedException()
            }
            404 -> {
                // 处理未找到
                throw NotFoundException()
            }
            in 500..599 -> {
                // 处理服务器错误
                throw ServerException()
            }
            else -> response
        }
    }
    .build()

四、最佳实践

  1. 单例模式:Retrofit 和 OkHttpClient 的创建成本较高,应该使用单例模式

  2. 合理配置超时时间:根据应用需求设置连接、读取和写入超时

  3. 日志拦截器:在 debug 版本中添加日志拦截器方便调试

  4. 错误处理:统一处理网络错误和业务错误

  5. 进度监听:对于大文件上传下载,实现进度监听

  6. HTTPS 安全配置:正确配置 HTTPS 证书验证

五、完整示例代码

object RetrofitClient {
    private const val BASE_URL = "https://api.example.com/"
    
    private val okHttpClient by lazy {
        OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = if (BuildConfig.DEBUG) {
                    HttpLoggingInterceptor.Level.BODY
                } else {
                    HttpLoggingInterceptor.Level.NONE
                }
            })
            .addInterceptor { chain ->
                val originalRequest = chain.request()
                val request = originalRequest.newBuilder()
                    .header("Authorization", "Bearer ${getToken()}")
                    .header("Accept", "application/json")
                    .method(originalRequest.method, originalRequest.body)
                    .build()
                chain.proceed(request)
            }
            .build()
    }
    
    private val retrofit by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    val apiService: ApiService by lazy {
        retrofit.create(ApiService::class.java)
    }
    
    private fun getToken(): String {
        // 从 SharedPreferences 或其他地方获取 token
        return ""
    }
}

// 使用示例
lifecycleScope.launch {
    try {
        val users = RetrofitClient.apiService.getUsers(page = 1)
        // 更新 UI
    } catch (e: Exception) {
        // 处理错误
    }
}

六、总结

OkHttp 和 Retrofit 的结合为 Android 网络请求提供了强大而灵活的解决方案。OkHttp 负责底层的网络通信,而 Retrofit 则提供了更高层次的抽象,使网络请求的代码更加简洁和易于维护。通过合理配置和扩展,可以满足各种复杂的网络请求需求。

在实际项目中,我们可以根据具体需求进一步扩展,例如添加请求重试机制、自定义数据解析器、集成 RxJava 或 Coroutines 等。掌握这两者的结合使用,将大大提高 Android 应用的网络请求效率和代码质量。


网站公告

今日签到

点亮在社区的每一天
去签到