前言
在现代 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()
四、最佳实践
单例模式:Retrofit 和 OkHttpClient 的创建成本较高,应该使用单例模式
合理配置超时时间:根据应用需求设置连接、读取和写入超时
日志拦截器:在 debug 版本中添加日志拦截器方便调试
错误处理:统一处理网络错误和业务错误
进度监听:对于大文件上传下载,实现进度监听
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 应用的网络请求效率和代码质量。