几乎没有 Android 应用不需要联网。列表加载、用户登录、上传图片、推送消息——这些功能的背后都有一个共同的基石:HTTP 网络请求。早期的 Android 开发常用 HttpURLConnection 或 Apache HttpClient,写起来样板代码多、线程管理繁琐、解析响应还得手写 JSON 解析逻辑。
直到 Square 公司先后开源了 OkHttp 和 Retrofit,局面才发生根本性改变。OkHttp 是一个高效、可定制的 HTTP 客户端,处理连接池、缓存、重定向、拦截器等底层细节。Retrofit 则在 OkHttp 之上做了一层声明式抽象,把 HTTP API 变成 Java/Kotlin 接口,开发者只需定义接口方法加几个注解,Retrofit 自动完成请求构造、参数序列化、响应反序列化。
一句话总结:OkHttp 管网络传输,Retrofit 管接口封装,两者配合是 Android 网络层的事实标准。
Retrofit 的核心思想是"接口即 API"。你不需要手动拼接 URL、设置请求头、构造 RequestBody,只需要:
interface ApiService {
@GET("users/{userId}")
suspend fun getUser(@Path("userId") id: String): Response<User>
}`@GET` 指定请求方式,`@Path` 替代路径参数,suspend 标记为挂起函数后可直接在协程中调用。Retrofit 在运行时会动态生成接口的实现类,你拿到的就是一个"活的"接口实例。
每次 Retrofit 请求最终都会交给 OkHttp 去真正发出去。OkHttp 负责连接建立、TLS 握手、请求排队、连接复用、超时控制。通过拦截器机制,你可以在请求发出前和响应返回后做很多事情:添加公共请求头、打印日志、重试失败请求、缓存策略等。
Retrofit 本身不关心响应体是什么格式,需要配合 Converter 来转换。最常见的是 Moshi 或 Gson:
Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create())这样 Retrofit 就会自动把 JSON 响应反序列化成你指定的 Kotlin 数据类。
// build.gradle.kts (module)
dependencies {
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
implementation("com.squareup.moshi:moshi-kotlin:1.15.1")
}import com.squareup.moshi.JsonClass
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query
@JsonClass(generateAdapter = true)
data class User(
val id: Long,
val name: String,
val email: String
)
@JsonClass(generateAdapter = true)
data class UserListResponse(
val data: List<User>,
val total: Int
)
interface ApiService {
@GET("api/users")
suspend fun getUsers(
@Query("page") page: Int = 1,
@Query("limit") limit: Int = 20
): Response<UserListResponse>
}import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.util.concurrent.TimeUnit
object RetrofitClient {
private const val BASE_URL = "https://api.example.com/"
private val okHttpClient: OkHttpClient by lazy {
val logging = HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor { chain ->
val request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer YOUR_TOKEN")
.addHeader("Accept", "application/json")
.build()
chain.proceed(request)
}
.addInterceptor(logging)
.build()
}
val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(MoshiConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class UserListViewModel : ViewModel() {
private val _users = MutableLiveData<List<User>>()
val users: LiveData<List<User>> = _users
private val _error = MutableLiveData<String>()
val error: LiveData<String> = _error
fun loadUsers(page: Int = 1) {
viewModelScope.launch {
try {
val response = RetrofitClient.apiService.getUsers(page)
if (response.isSuccessful) {
_users.value = response.body()?.data ?: emptyList()
} else {
_error.value = "请求失败:${response.code()}"
}
} catch (e: Exception) {
_error.value = "网络异常:${e.message}"
}
}
}
}核心要点:用 `viewModelScope.launch` 发起协程,Retrofit 的 suspend 函数自动在后台线程执行网络请求,不需要手动切线程。`Response<T>` 可以同时拿到状态码和解析后的 body,方便做错误处理。
**baseUrl 要以斜杠结尾。** 如果写 `"https://api.example.com"` 而不是 `"https://api.example.com/"`,接口中的 `/api/users` 会被解析为完整的 `api/users`,导致路径拼接异常。这是新人最容易踩的坑。
**不要每次请求都创建 Retrofit 实例。** Retrofit 和 OkHttpClient 中有连接池、线程池等重量资源,创建开销大。应该用单例或依赖注入框架(如 Hilt)管理。
**区分 suspend 和 Call。** 用 suspend 函数时异常会被抛出,需要在 try-catch 中捕获;用 `Call<T>` 时则通过 `enqueue` 回调处理。协程项目建议统一用 suspend。
**拦截器顺序很重要。** 先添加的拦截器在请求链的外层先执行、内层后执行。日志拦截器一般放在最后,这样能记录最终发出的完整请求,包括前面拦截器添加的请求头。
**不要忘记关闭响应体。** 虽然 Retrofit 处理了大部分情况,但在用 `ResponseBody` 时,记得 close。另外,`Response<T>` 的 body 在协程场景下会自动管理,普通场景下需要留意。
**生产环境关闭详细日志。** `HttpLoggingInterceptor.Level.BODY` 会打印请求体和响应体,可能泄露敏感信息(密钥、用户数据)。上线前建议切换到 `Level.NONE` 或仅保留 `Level.HEADERS`。
Retrofit + OkHttp 把网络请求从"手写样板代码"变成了"声明接口 + 配置客户端"的简洁范式。你定义数据类描述响应结构,用注解描述 API 形态,OkHttp 保证传输质量,Retrofit 负责胶水代码。配合 Kotlin 协程的 suspend 函数,整个调用链简洁、可读、不易出错。
掌握了这套工具,再结合之前学过的 ViewModel + LiveData,就能搭建出一条完整的数据通道:网络请求(Retrofit)→ 状态管理(ViewModel)→ UI 更新(LiveData)。这正是 MVVM 架构中最经典的数据流向。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。