"请求到底怎么流动",再拆 Retrofit 和 OkHttp 的源码协作,重点看 OkHttp 的责任链模式,最后聊从 RxJava 切到 Kotlin 协程时怎么做、阵痛在哪里、共性是什么。
一句话结论
Retrofit 负责把"接口方法"翻译成一次 HTTP 调用,OkHttp 负责真正执行网络请求。Retrofit 像一个声明式 API 翻译器,OkHttp 像一台可插拔的网络执行引擎。
text
你写的接口方法
↓ Retrofit 动态代理
解析注解、参数、返回类型
↓ ServiceMethod
生成 OkHttp Request
↓ OkHttpCall
交给 OkHttp RealCall
↓ RealInterceptorChain
责任链拦截器逐层处理
↓ 网络 I/O
拿到 Response
↓ Converter
转成业务对象
↓ CallAdapter
适配成 Call / RxJava / suspend / Flow 包装
1. 为什么 Retrofit 和 OkHttp 经常一起出现
Retrofit 解决什么
你不想每个接口都手写 URL、参数拼接、JSON 解析、错误映射,所以 Retrofit 允许你这样声明:
kotlin
interface UserApi {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Long): User
}
它关心的是:
- 这个方法是什么 HTTP method?
- URL 怎么拼?
- 参数从哪里来?
- Body 怎么序列化?
- Response 怎么反序列化?
- 返回值要适配成什么形式?
OkHttp 解决什么
OkHttp 关心的是:
- 请求怎么排队?
- 连接怎么复用?
- 缓存怎么处理?
- 重试和重定向怎么做?
- 拦截器怎么执行?
- Socket 怎么读写?
两者分工
| 框架 | 角色 | 更像什么 |
|---|---|---|
| Retrofit | 声明式接口层 | 翻译器 / 适配层 |
| OkHttp | HTTP 执行层 | 网络引擎 |
| Converter | 数据转换层 | JSON 转换器 |
| CallAdapter | 返回类型适配层 | 异步模型适配器 |
2. Retrofit 创建接口对象:动态代理
你写的代码
kotlin
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient)
.addConverterFactory(MoshiConverterFactory.create())
.build()
val api = retrofit.create(UserApi::class.java)
源码原理
Retrofit 的 create() 会给接口创建一个动态代理。你调用 api.getUser(1) 时,并不是直接进入某个真实实现类,而是进入代理对象的 InvocationHandler。
伪代码:
kotlin
fun <T> create(service: Class<T>): T {
validateServiceInterface(service)
return Proxy.newProxyInstance(
service.classLoader,
arrayOf(service)
) { proxy, method, args ->
val serviceMethod = loadServiceMethod(method)
serviceMethod.invoke(proxy, args)
} as T
}
为什么这么实现
如果不用动态代理,你就要为每个接口写实现类:
kotlin
class UserApiImpl : UserApi {
override suspend fun getUser(id: Long): User {
// 手写 URL、Request、Response 解析
}
}
动态代理的好处是:
- 业务只写接口,不写样板实现。
- Retrofit 可以统一拦截所有接口方法调用。
- 注解解析和请求构建逻辑集中在框架内部。
- 后续支持
Call、RxJava、协程,只需要扩展适配层。
3. Retrofit 如何解析一个接口方法
接口方法
kotlin
interface UserApi {
@GET("users/{id}")
suspend fun getUser(
@Path("id") id: Long,
@Query("detail") detail: Boolean
): User
}
Retrofit 要解析的信息
text
方法级注解:
@GET("users/{id}") -> HTTP method + relativeUrl
参数注解:
@Path("id") -> 替换路径
@Query("detail") -> 拼 query
返回类型:
suspend fun ... : User -> 协程返回 User
转换器:
ResponseBody -> User
调用适配器:
OkHttpCall -> suspend 返回
ServiceMethod
Retrofit 会把一个 Java/Kotlin 方法解析成 ServiceMethod。它可以理解为"接口方法的执行说明书"。
伪代码:
kotlin
class ServiceMethod(
val requestFactory: RequestFactory,
val callFactory: Call.Factory,
val responseConverter: Converter<ResponseBody, Any>,
val callAdapter: CallAdapter<Any, Any>
) {
fun invoke(args: Array<Any?>): Any {
val request = requestFactory.create(args)
val call = OkHttpCall(callFactory, request, responseConverter)
return callAdapter.adapt(call)
}
}
为什么要缓存 ServiceMethod
同一个接口方法会被调用很多次。如果每次都反射解析注解,成本太高。Retrofit 会缓存解析结果。
text
第一次调用 getUser:
反射解析注解
创建 ServiceMethod
放入缓存
后续调用 getUser:
直接从缓存取 ServiceMethod
好处:
- 减少反射成本。
- 每次调用只关心参数值。
- 框架结构更清晰:解析一次,执行多次。
4. Converter:ResponseBody 如何变成业务对象
常见配置
kotlin
Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create())
.build()
原理
OkHttp 返回的是 ResponseBody。业务要的是 User、List<User>、ApiResult<User>。
Converter 的职责就是类型转换:
text
ResponseBody:
{"id":1,"name":"Tom"}
Converter:
JSON -> User
业务层:
User(id=1, name="Tom")
伪代码:
kotlin
interface Converter<F, T> {
fun convert(value: F): T
}
class JsonUserConverter : Converter<ResponseBody, User> {
override fun convert(value: ResponseBody): User {
val json = value.string()
return jsonParser.fromJson(json, User::class.java)
}
}
好处
- Retrofit 不绑定具体 JSON 框架。
- 可以替换 Gson、Moshi、Kotlinx Serialization。
- 请求 Body 和响应 Body 的转换逻辑可插拔。
5. CallAdapter:返回类型如何适配
同一个 HTTP 请求,不同返回方式
kotlin
interface UserApi {
@GET("users/{id}")
fun getUserCall(@Path("id") id: Long): Call<User>
@GET("users/{id}")
fun getUserSingle(@Path("id") id: Long): Single<User>
@GET("users/{id}")
suspend fun getUserSuspend(@Path("id") id: Long): User
}
底层都可以是一套 HTTP 调用,但外层返回模型不同。
原理
text
OkHttpCall<User>
↓ CallAdapter
Call<User>
或 Single<User>
或 suspend 的挂起结果
伪代码:
kotlin
interface CallAdapter<R, T> {
fun responseType(): Type
fun adapt(call: Call<R>): T
}
好处
- Retrofit 核心不需要硬编码所有异步框架。
- RxJava、Guava、Java8、协程都可以通过适配层接入。
- 同一套接口注解可以迁移到不同异步模型。
6. OkHttp 的请求执行入口
Retrofit 最终交给 OkHttp
Retrofit 内部会创建 OkHttp 的 Request,然后调用 OkHttp 的 Call.Factory。
kotlin
val request: Request = requestFactory.create(args)
val call: okhttp3.Call = okHttpClient.newCall(request)
同步和异步
kotlin
call.execute() // 同步执行
call.enqueue(callback) // 异步执行
在 Android 主线程不能直接 execute() 做网络请求。Retrofit 的协程和 RxJava 适配通常会帮你把异步模型包装得更舒服,但底层仍然是 OkHttp Call。
7. OkHttp Dispatcher:请求如何排队
Dispatcher 做什么
OkHttp 的 Dispatcher 管理异步请求队列,包括:
- 正在运行的异步请求。
- 等待中的异步请求。
- 同域名最大并发数。
- 全局最大并发数。
伪代码:
kotlin
class Dispatcher {
val readyAsyncCalls = ArrayDeque<AsyncCall>()
val runningAsyncCalls = ArrayDeque<AsyncCall>()
fun enqueue(call: AsyncCall) {
if (canRunMoreCalls()) {
runningAsyncCalls += call
executorService.execute(call)
} else {
readyAsyncCalls += call
}
}
fun finished(call: AsyncCall) {
runningAsyncCalls -= call
promoteAndExecute()
}
}
好处
- 避免无限制创建网络请求。
- 控制同一 host 的并发。
- 请求完成后自动推进等待队列。
- 网络层调度和业务层调用解耦。
8. OkHttp 责任链模式总览
OkHttp 最经典的设计就是拦截器责任链。一次请求会按顺序经过多个拦截器,每个拦截器可以:
- 修改 Request。
- 继续调用下一个拦截器。
- 拿到 Response 后再加工。
- 在特殊情况下直接返回 Response。
- 抛出异常终止链路。
简化链路
text
Application Interceptors
↓
RetryAndFollowUpInterceptor
↓
BridgeInterceptor
↓
CacheInterceptor
↓
ConnectInterceptor
↓
Network Interceptors
↓
CallServerInterceptor
RealInterceptorChain 伪代码
kotlin
class RealInterceptorChain(
private val interceptors: List<Interceptor>,
private val index: Int,
private val request: Request
) : Interceptor.Chain {
override fun proceed(request: Request): Response {
val next = RealInterceptorChain(
interceptors = interceptors,
index = index + 1,
request = request
)
val interceptor = interceptors[index]
return interceptor.intercept(next)
}
}
Interceptor 伪代码
kotlin
class HeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val oldRequest = chain.request()
val newRequest = oldRequest.newBuilder()
.addHeader("token", tokenProvider.token())
.build()
val response = chain.proceed(newRequest)
return response
}
}
9. 责任链模式为什么适合网络框架
网络请求天然是流水线
一次 HTTP 请求不是"发出去,拿回来"这么简单,中间有很多阶段:
text
补 Header
处理 Cookie
检查缓存
失败重试
重定向
建立连接
写请求体
读响应体
打印日志
统一错误处理
如果全写在一个大方法里,会变成很难维护的巨型流程。
责任链的好处
| 好处 | 说明 |
|---|---|
| 职责单一 | 每个拦截器只处理一种横切逻辑 |
| 顺序清晰 | 链表式执行,前后关系明确 |
| 可插拔 | 业务可以添加自定义拦截器 |
| 可复用 | Header、日志、认证、缓存逻辑能独立复用 |
| 可测试 | 每个拦截器可以单独测试 |
| 双向处理 | Request 往下走,Response 往回走 |
双向处理模型
text
请求方向:
A -> B -> C -> Server
响应方向:
Server -> C -> B -> A
所以一个日志拦截器可以在 proceed() 前记录请求,在 proceed() 后记录响应。
10. OkHttp 内置拦截器做什么
RetryAndFollowUpInterceptor
负责失败恢复、重试、重定向等后续请求。
text
发送请求
如果需要重定向:
构造新 Request
再走一次链路
如果连接失败且允许重试:
重试
否则:
返回响应或抛异常
BridgeInterceptor
在用户请求和网络请求之间做桥接,例如添加一些协议层 Header、处理 gzip。
text
用户 Request:
只关心业务 Header
Bridge:
补充 Host、Connection、Accept-Encoding、Cookie 等
网络 Response:
如果 gzip,解压给上层
CacheInterceptor
根据缓存策略决定:
- 直接用缓存。
- 直接走网络。
- 条件缓存验证。
- 合并缓存和网络响应。
ConnectInterceptor
负责找到可用连接,建立或复用连接。
text
从连接池找连接
如果可复用:
使用已有连接
否则:
建立新连接
CallServerInterceptor
真正把请求写到服务器,并读取响应。
text
写请求头
写请求体
读响应头
读响应体
返回 Response
11. Application Interceptor 和 Network Interceptor
Application Interceptor
添加方式:
kotlin
OkHttpClient.Builder()
.addInterceptor(AuthInterceptor())
.build()
特点:
- 更靠近业务层。
- 通常只执行一次逻辑。
- 看不到中间重定向的每一次网络请求细节。
- 适合统一 Header、日志、业务错误处理。
Network Interceptor
添加方式:
kotlin
OkHttpClient.Builder()
.addNetworkInterceptor(NetworkLogInterceptor())
.build()
特点:
- 更靠近真实网络。
- 能观察每次网络交换。
- 可以访问连接信息。
- 适合底层网络诊断。
选择建议
| 场景 | 推荐 |
|---|---|
| 加 token | Application Interceptor |
| 统一业务 header | Application Interceptor |
| 打印业务请求日志 | Application Interceptor |
| 观察重定向过程 | Network Interceptor |
| 诊断连接和网络层 | Network Interceptor |
12. Retrofit + OkHttp 完整协作伪代码
kotlin
interface Api {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Long): User
}
val okHttp = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor())
.addInterceptor(LogInterceptor())
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttp)
.addConverterFactory(MoshiConverterFactory.create())
.build()
val api = retrofit.create(Api::class.java)
val user = api.getUser(1L)
执行过程:
text
api.getUser(1)
↓
动态代理拦截方法调用
↓
读取 getUser 方法对应的 ServiceMethod
↓
根据 @GET、@Path 创建 Request
↓
OkHttpClient.newCall(request)
↓
RealCall.enqueue/execute
↓
RealInterceptorChain.proceed
↓
内置和自定义拦截器逐个处理
↓
CallServerInterceptor 访问网络
↓
ResponseBody 返回给 Retrofit
↓
Converter 转成 User
↓
suspend 函数恢复,返回 User
13. 老项目里的 RxJava + Retrofit
典型接口
kotlin
interface UserApi {
@GET("users/{id}")
fun getUser(@Path("id") id: Long): Single<User>
}
典型调用
kotlin
api.getUser(1L)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ user -> showUser(user) },
{ error -> showError(error) }
)
这套写法解决了什么
- 把网络请求放到 IO 线程。
- 把 UI 更新切回主线程。
- 用链式操作符组合异步任务。
- 用
Disposable取消订阅。
常见问题
kotlin
private val disposables = CompositeDisposable()
override fun onDestroy() {
disposables.clear()
}
如果忘记清理,页面销毁后请求还可能回调 UI,引发生命周期问题。
14. RxJava 配合 Retrofit 的源码思路
Retrofit 支持 RxJava 靠的是 CallAdapter。
text
接口返回 Single<User>
↓
Retrofit 查找 RxJava CallAdapter
↓
把 OkHttpCall<User> 包装成 Single<User>
↓
subscribe 时触发网络请求
伪代码:
kotlin
class RxJavaCallAdapter<R> : CallAdapter<R, Single<R>> {
override fun adapt(call: Call<R>): Single<R> {
return Single.create { emitter ->
call.enqueue(object : Callback<R> {
override fun onResponse(call: Call<R>, response: Response<R>) {
if (response.isSuccessful) {
emitter.onSuccess(response.body()!!)
} else {
emitter.onError(HttpException(response))
}
}
override fun onFailure(call: Call<R>, t: Throwable) {
emitter.onError(t)
}
})
emitter.setCancellable {
call.cancel()
}
}
}
}
好处
- Retrofit 不直接依赖业务如何订阅。
- RxJava 的线程切换、组合、错误处理继续生效。
Disposable.dispose()可以映射到底层Call.cancel()。
15. Kotlin 协程版 Retrofit
接口写法
kotlin
interface UserApi {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Long): User
}
调用:
kotlin
viewModelScope.launch {
try {
val user = api.getUser(1L)
_uiState.value = UiState.Content(user)
} catch (e: Exception) {
_uiState.value = UiState.Error("加载失败")
}
}
Retrofit 如何支持 suspend
Retrofit 会识别接口方法是否是 Kotlin suspend 方法。suspend 方法在 JVM 层会多一个 Continuation 参数,Retrofit 通过这个特征进入协程适配逻辑。
伪代码:
text
解析方法返回类型:
如果最后一个参数是 Continuation:
这是 suspend 方法
走 SuspendForBody 或 SuspendForResponse
否则:
走普通 CallAdapter
协程挂起流程:
text
suspend fun getUser()
↓
Retrofit 创建 OkHttpCall
↓
enqueue 异步请求
↓
当前协程挂起
↓
OkHttp 回调成功
↓
Converter 转 User
↓
Continuation.resume(user)
↓
协程从挂起点继续执行
好处
- 调用代码像同步一样直。
- 取消跟协程 Job 绑定。
- ViewModel 生命周期结束时可自动取消。
- 错误处理可以回到普通
try/catch。
16. 从 RxJava 切到协程怎么做
第一步:接口返回类型迁移
RxJava:
kotlin
@GET("users/{id}")
fun getUser(@Path("id") id: Long): Single<User>
协程:
kotlin
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Long): User
如果需要拿到 HTTP 状态码:
kotlin
@GET("users/{id}")
suspend fun getUserResponse(@Path("id") id: Long): Response<User>
第二步:调用层迁移
RxJava:
kotlin
disposables += api.getUser(id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(::showUser, ::showError)
协程:
kotlin
viewModelScope.launch {
runCatching {
api.getUser(id)
}.onSuccess { user ->
_uiState.value = UiState.Content(user)
}.onFailure { error ->
_uiState.value = UiState.Error(error.message ?: "加载失败")
}
}
第三步:线程切换迁移
RxJava:
kotlin
api.getUsers()
.subscribeOn(Schedulers.io())
.map { users -> heavyMap(users) }
.observeOn(AndroidSchedulers.mainThread())
协程:
kotlin
viewModelScope.launch {
val users = api.getUsers()
val uiModels = withContext(Dispatchers.Default) {
heavyMap(users)
}
_uiState.value = UiState.Content(uiModels)
}
Retrofit 的 suspend 网络等待本身不需要你手动 withContext(Dispatchers.IO) 包一层,但本地文件、数据库、大计算仍然要切到合适 Dispatcher。
第四步:生命周期迁移
RxJava:
kotlin
override fun onDestroy() {
disposables.clear()
}
协程:
kotlin
class UserViewModel : ViewModel() {
fun load() {
viewModelScope.launch {
api.getUser(1L)
}
}
}
ViewModel 清除时,viewModelScope 会取消内部协程。
17. 阵痛期会痛在哪里
1. 返回类型思维变化
RxJava 习惯:
kotlin
fun getUser(): Single<User>
协程习惯:
kotlin
suspend fun getUser(): User
痛点:以前"异步"体现在返回类型里,现在体现在函数修饰符和调用上下文里。
2. 操作符迁移
RxJava:
kotlin
api.search(keyword)
.debounce(300, TimeUnit.MILLISECONDS)
.switchMap { api.search(it) }
Flow:
kotlin
keywordFlow
.debounce(300)
.flatMapLatest { api.searchFlow(it) }
痛点:名字相似但语义细节不完全一样,团队需要重新统一写法。
3. 错误处理变化
RxJava:
kotlin
.onErrorReturn { emptyList() }
协程:
kotlin
val users = runCatching {
repository.getUsers()
}.getOrElse {
emptyList()
}
Flow:
kotlin
flow.catch { emit(emptyList()) }
痛点:普通 suspend 用 try/catch,Flow 用 catch,并发任务还要理解异常传播。
4. 取消语义变化
RxJava 取消:
kotlin
disposable.dispose()
协程取消:
kotlin
job.cancel()
痛点:协程取消是协作式的,不能随便吞掉 CancellationException。
5. 测试方式变化
RxJava 常见:
kotlin
RxJavaPlugins.setIoSchedulerHandler { Schedulers.trampoline() }
协程常见:
kotlin
@Test
fun load() = runTest {
viewModel.load()
advanceUntilIdle()
assertTrue(viewModel.uiState.value is UiState.Content)
}
痛点:要理解测试 Dispatcher、虚拟时间、Flow 收集。
18. RxJava 和协程有什么共性
| 共性 | RxJava | Kotlin 协程 |
|---|---|---|
| 异步任务 | Single、Observable |
suspend、Deferred |
| 流式数据 | Observable、Flowable |
Flow |
| 线程切换 | subscribeOn、observeOn |
withContext、Dispatcher |
| 取消 | Disposable |
Job |
| 错误处理 | onError... |
try/catch、catch |
| 组合任务 | zip、flatMap |
async/await、combine、flatMapLatest |
| 生命周期绑定 | AutoDispose / 手动 clear | viewModelScope、repeatOnLifecycle |
关键理解
RxJava 和协程都在解决异步编排问题。区别是:
- RxJava 更像"数据流操作库"。
- 协程更像"语言级异步模型"。
- Flow 补上了协程中的流式数据能力。
19. 迁移推荐策略
不推荐一刀切
不要把全项目所有接口一次性从 RxJava 改成 suspend。风险太高。
推荐分层迁移
text
新接口:
直接用 suspend
老接口:
保持 RxJava,按模块迁移
Repository:
对外逐步暴露 suspend
ViewModel:
新页面用 viewModelScope
UI:
状态统一 StateFlow
过渡期适配
如果底层还是 RxJava,可以先在 Repository 转成 suspend。
伪代码:
kotlin
suspend fun <T : Any> Single<T>.awaitValue(): T =
suspendCancellableCoroutine { continuation ->
val disposable = subscribe(
{ value -> continuation.resume(value) },
{ error -> continuation.resumeWithException(error) }
)
continuation.invokeOnCancellation {
disposable.dispose()
}
}
这样 ViewModel 可以先切到协程,而数据源暂时不动。
20. 推荐的 Android 落地写法
Api
kotlin
interface UserApi {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Long): UserDto
}
Repository
kotlin
class UserRepository(
private val api: UserApi
) {
suspend fun getUser(id: Long): AppResult<User> {
return try {
val user = api.getUser(id).toDomain()
AppResult.Success(user)
} catch (e: CancellationException) {
throw e
} catch (e: HttpException) {
AppResult.Failure("服务异常:${e.code()}")
} catch (e: IOException) {
AppResult.Failure("网络异常")
} catch (e: Exception) {
AppResult.Failure("未知异常")
}
}
}
ViewModel
kotlin
class UserViewModel(
private val repository: UserRepository
) : ViewModel() {
private val _uiState = MutableStateFlow<UserUiState>(UserUiState.Loading)
val uiState: StateFlow<UserUiState> = _uiState
fun loadUser(id: Long) {
viewModelScope.launch {
_uiState.value = UserUiState.Loading
_uiState.value = when (val result = repository.getUser(id)) {
is AppResult.Success -> UserUiState.Content(result.data)
is AppResult.Failure -> UserUiState.Error(result.message)
}
}
}
}
Fragment 收集
kotlin
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
render(state)
}
}
}
21. 业务拦截器实战
Token 拦截器
kotlin
class AuthInterceptor(
private val tokenProvider: TokenProvider
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val token = tokenProvider.token()
val request = chain.request()
.newBuilder()
.addHeader("Authorization", "Bearer $token")
.build()
return chain.proceed(request)
}
}
统一错误拦截器
kotlin
class BusinessErrorInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
if (response.code == 401) {
// 通知登录过期,或触发刷新 token 流程
}
return response
}
}
注意
拦截器里不要随便读取 response.body.string(),因为 body 只能消费一次。日志框架通常会复制或缓冲内容再重新构造 ResponseBody。
22. 面试怎么讲
可以按这个顺序:
text
1. Retrofit 通过动态代理创建接口实现。
2. 调用接口方法时,解析或读取缓存的 ServiceMethod。
3. ServiceMethod 根据注解和参数生成 OkHttp Request。
4. OkHttpClient.newCall 创建 RealCall。
5. RealCall 通过 Dispatcher 管理异步请求。
6. 真正执行时进入 RealInterceptorChain。
7. 请求依次经过自定义拦截器和内置拦截器。
8. CallServerInterceptor 完成网络读写。
9. ResponseBody 回到 Retrofit,由 Converter 转成业务对象。
10. 最后由 CallAdapter 适配为 Call、RxJava 类型或协程 suspend 返回。
责任链模式一句话
OkHttp 用责任链把网络请求拆成多个可插拔阶段,每个拦截器只处理自己的职责,并通过 chain.proceed() 把请求交给下一个节点,响应再沿原路返回。
RxJava 到协程一句话
从 RxJava 切到协程,本质是从"返回一个异步流对象,然后订阅它",变成"在协程作用域中调用 suspend 函数,让异步代码写得像顺序代码",而 Flow 负责承接持续数据流场景。
23. 源码入口
以下源码路径按 2026-09-08 查询官方仓库整理:
| 主题 | 源码入口 |
|---|---|
| Retrofit 动态代理 | Retrofit.java |
| Retrofit 方法解析 | ServiceMethod.java |
| Retrofit suspend 适配 | HttpServiceMethod.java |
| Retrofit 协程扩展 | KotlinExtensions.kt |
| OkHttp RealCall | RealCall.kt |
| OkHttp 责任链 | RealInterceptorChain.kt |
| OkHttp Dispatcher | Dispatcher.kt |
| Android 协程建议 | Android Kotlin Coroutines |
24. 总结
Retrofit 和 OkHttp 的协作,本质是"声明式接口层"和"网络执行引擎"的组合。Retrofit 通过动态代理、注解解析、Converter、CallAdapter 把接口方法变成 HTTP 调用;OkHttp 通过 Dispatcher 和责任链拦截器把请求稳定、高扩展地执行出去。
RxJava 到协程的迁移,不是简单替换几个返回类型,而是异步思维的调整:从订阅链转向结构化并发,从 Disposable 转向 Job,从 observeOn 转向生命周期感知的状态收集。阵痛期会有,但它们解决的问题高度相似。真正迁移顺了以后,ViewModel 里的网络请求会更直观,生命周期也更容易收住。