Retrofit + Kotlin 协程(Android 实战教程)
这是 Android 开发里最主流的网络请求方案:
Retrofit + Coroutines + MVVM
现代 Android 项目基本都这么写。
这一篇会从:
- Retrofit 基础
- suspend 网络请求
- 协程切线程
- MVVM 实战
- 错误处理
- Flow 配合
- 封装最佳实践
一路讲到项目级写法。
一、Retrofit 是什么?
Retrofit 是 Square 出的网络请求库。
作用: 把 HTTP API 变成 Kotlin 接口
| 以前 | Retrofit 之后 |
|---|---|
| HttpURLConnection / OkHttp | api.getUser() |
| 非常麻烦 | 直接像调用本地函数 |
二、Retrofit 为什么和协程绝配?
以前 Retrofit:
kotlin
Call.enqueue()
回调地狱:
kotlin
api.getUser().enqueue(...)
协程之后:
kotlin
val user = api.getUser()
像同步代码。但底层仍然是异步。
这就是 suspend + Retrofit 的威力。
三、添加依赖
kotlin
// Retrofit
implementation "com.squareup.retrofit2:retrofit:2.11.0"
implementation "com.squareup.retrofit2:converter-gson:2.11.0"
// 协程
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.0"
四、Retrofit 基础配置
五、创建 Data 类
kotlin
data class User(
val id: Int,
val name: String
)
六、创建 API 接口
这是 Retrofit 核心。
kotlin
interface ApiService {
@GET("user")
suspend fun getUser(): User
}
重点: suspend
Retrofit 会自动支持协程。
七、创建 Retrofit
kotlin
object RetrofitManager {
val api: ApiService by lazy {
Retrofit.Builder()
.baseUrl("https://example.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ApiService::class.java)
}
}
八、第一个协程网络请求
ViewModel
kotlin
class UserViewModel : ViewModel() {
fun loadUser() {
viewModelScope.launch {
val user = RetrofitManager.api.getUser()
println(user.name)
}
}
}
九、为什么 suspend 不需要 enqueue?
| 以前 | 现在 |
|---|---|
enqueue(callback) |
suspend fun |
Retrofit 内部已经帮你做了:
- 异步线程
Continuation.resume()
这就是协程适配器。
十、Retrofit + Continuation 原理
你写:
kotlin
suspend fun getUser(): User
Retrofit 底层其实拿到了: Continuation<User>
网络返回后:continuation.resume(user),协程恢复。
十一、为什么不会阻塞主线程?
很多人疑惑:
kotlin
viewModelScope.launch {
api.getUser() // 不是在 Main 线程吗?
}
为什么不卡 UI?
因为:Retrofit 内部自动切到 OkHttp 线程池,网络完成后再恢复协程。
所以:你看起来像同步,实际上是异步。
十二、withContext 什么时候需要?
Retrofit 请求本身
不需要 withContext(IO),因为 Retrofit 已经异步。
但 JSON 大解析需要
kotlin
val result = withContext(Dispatchers.Default) {
parseBigJson()
}
数据库操作
kotlin
withContext(Dispatchers.IO)
十三、POST 请求
API
kotlin
interface ApiService {
@POST("login")
suspend fun login(@Body body: LoginRequest): LoginResponse
}
Request
kotlin
data class LoginRequest(
val username: String,
val password: String
)
十四、Query 参数
kotlin
@GET("user")
suspend fun getUser(@Query("id") id: Int): User
// 请求:/user?id=1
十五、Path 参数
kotlin
@GET("user/{id}")
suspend fun getUser(@Path("id") id: Int): User
// 请求:/user/1
十六、错误处理(非常重要)
很多人项目里直接崩。正确写法:
kotlin
viewModelScope.launch {
try {
val user = api.getUser()
} catch (e: Exception) {
e.printStackTrace()
}
}
十七、为什么会抛异常?
Retrofit 协程:网络失败会直接 throw Exception,而不是 onFailure()。
十八、项目级错误封装(推荐)
ResultState
kotlin
sealed class ResultState<out T> {
data class Success<T>(val data: T) : ResultState<T>()
data class Error(val msg: String) : ResultState<Nothing>()
object Loading : ResultState<Nothing>()
}
十九、统一请求封装
kotlin
suspend fun <T> safeApiCall(apiCall: suspend () -> T): ResultState<T> {
return try {
ResultState.Success(apiCall())
} catch (e: Exception) {
ResultState.Error(e.message ?: "未知错误")
}
}
二十、使用方式
kotlin
viewModelScope.launch {
when (val result = safeApiCall { api.getUser() }) {
is ResultState.Success -> {
// 处理成功
}
is ResultState.Error -> {
// 处理错误
}
else -> {}
}
}
二十一、Repository 层(MVVM核心)
现代 Android 必须分层。
二十二、Repository
kotlin
class UserRepository {
suspend fun getUser(): User {
return RetrofitManager.api.getUser()
}
}
二十三、ViewModel
kotlin
class UserViewModel : ViewModel() {
private val repository = UserRepository()
fun load() {
viewModelScope.launch {
val user = repository.getUser()
}
}
}
二十四、为什么需要 Repository?
因为 ViewModel 不应该直接操作 Retrofit,否则:
- 耦合严重
- 不好测试
- 难维护
二十五、Flow + Retrofit(现代方案)
这是现在最推荐的。
Repository
kotlin
class UserRepository {
fun getUser() = flow {
emit(ResultState.Loading)
try {
val user = api.getUser()
emit(ResultState.Success(user))
} catch (e: Exception) {
emit(ResultState.Error("请求失败"))
}
}
}
ViewModel
kotlin
fun loadUser() {
viewModelScope.launch {
repository.getUser().collect {
// 处理状态
}
}
}
二十六、Flow 的优势
比 suspend 更适合:
- UI状态
- Loading
- 连续数据
- 重试
- 分页
二十七、Retrofit + OkHttp
Retrofit 底层其实是 OkHttp。
二十八、添加日志拦截器
依赖
kotlin
implementation "com.squareup.okhttp3:logging-interceptor:4.12.0"
配置
kotlin
val logging = HttpLoggingInterceptor()
logging.level = HttpLoggingInterceptor.Level.BODY
二十九、OkHttpClient
kotlin
val client = OkHttpClient.Builder()
.addInterceptor(logging)
.build()
三十、Retrofit 使用 client
kotlin
Retrofit.Builder()
.client(client)
三十一、拦截器(项目必会)
Token 拦截器
kotlin
class TokenInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
.newBuilder()
.addHeader("token", "xxx")
.build()
return chain.proceed(request)
}
}
三十二、超时设置
kotlin
OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
三十三、协程取消与 Retrofit
这是高频面试题。
当协程 cancel 时,Retrofit 会自动取消网络请求。
因为:Retrofit 协程和 Job 已关联。
三十四、真正的项目结构(推荐)
ui/
viewmodel/
repository/
network/
model/
三十五、标准企业级结构
| 层级 | 职责 |
|---|---|
| ApiService | 定义网络接口 |
| RetrofitManager | Retrofit 配置管理 |
| Repository | 数据仓储,隔离网络层 |
| ViewModel | 业务逻辑,UI状态管理 |
| UI | Activity / Fragment / Compose |
三十六、Compose + Retrofit
在 Jetpack Compose 中:
kotlin
LaunchedEffect(Unit) {
viewModel.load()
}
ViewModel:viewModelScope.launch
这是现代 Android 官方方案。
三十七、Retrofit 常见面试题
1. suspend 为什么不阻塞?
因为:Retrofit 底层 OkHttp异步 + Continuation恢复
2. Retrofit 为什么不需要 withContext(IO)?
因为:Retrofit 已经异步
3. Retrofit 底层是谁?
Retrofit
↓
OkHttp
4. 协程取消为什么能取消请求?
因为:Coroutine Job 关联 OkHttp Call.cancel()
5. suspend 本质是什么?
编译器:Continuation + 状态机
三十八、现代 Android 最推荐写法
ViewModel
kotlin
class UserViewModel : ViewModel() {
val uiState = MutableStateFlow<ResultState<User>>(ResultState.Loading)
fun loadUser() {
viewModelScope.launch {
uiState.value = ResultState.Loading
uiState.value = try {
ResultState.Success(api.getUser())
} catch (e: Exception) {
ResultState.Error("失败")
}
}
}
}
三十九、真正的大脑模型
以后看到 suspend fun getUser(),你脑子里应该自动出现:
Retrofit
↓
OkHttp异步请求
↓
Continuation挂起
↓
网络返回
↓
resume恢复协程
↓
继续执行
四十、总结
| 组件 | 作用 |
|---|---|
| Retrofit | HTTP → Kotlin 接口 |
| suspend | 协程挂起 + 异步 |
| OkHttp | 底层网络执行 |
| Repository | 隔离网络层 |
| ViewModel | 状态管理与业务逻辑 |
| StateFlow / Flow | UI状态响应 |
| ResultState | 统一错误处理 |
四十一、企业级最佳实践(非常重要)
不要这样
c
Activity -> Retrofit
要这样
bash
UI
↓
ViewModel
↓
Repository
↓
Retrofit
最后一句(真正理解 Retrofit + 协程)
Retrofit + 协程真正厉害的地方:
不是"代码变短"。
而是:
把异步回调变成了同步思维
底层:
bash
Continuation
+
状态机
+
OkHttp异步
上层:
bash
像写同步代码一样写异步
这就是现代 Android 网络架构的核心。