Android 网络深度系列 · 第 4 篇
系列导航:第1篇:HTTP协议全解 | 第2篇:HTTPS与网络安全 | 第3篇:OkHttp架构剖析 | 第4篇:Retrofit原理与实战 | 第5篇:WebSocket与长连接 | 第6篇:网络实战场景
前言
上一篇我们拆了 OkHttp 的骨架——拦截器链、连接池、缓存策略,明白了它是怎么"做"网络请求的。
这篇讲 Retrofit,它是怎么让网络请求变得"优雅"的。
Retrofit 是 Square 的另一个杰作。如果你是 Android 开发者,大概率每天都在用。但你有没有想过——为什么写个接口、加个注解,就能发起 HTTP 请求?那个接口明明没有实现类,调用时是怎么执行的?
答案藏在 动态代理 里。
⚠️ 本文基于 Retrofit 2.9.0 / 2.11.0 源码分析,所有示例使用 Kotlin。Retrofit 2.11 是当前最新稳定版,与 2.9.x 差异不大,但修复了一些协程相关的 bug。
1. Retrofit 的设计哲学
在动源码之前,先理解 Retrofit 的设计思路——搞懂了哲学,读代码才不迷路。
1.1 声明式 vs 命令式
这是 Retrofit 最核心的思想转变。
命令式:告诉机器每一步怎么做。
// 命令式——你要描述怎么构建请求、怎么执行
val request = Request.Builder()
.url("https://api.example.com/users/1")
.get()
.build()
val call = okHttpClient.newCall(request)
val response = call.execute()
val body = response.body?.string()
// 然后还要自己解析 JSON...
声明式:告诉机器你要什么,由框架解决怎么做的细节。
// 声明式——只描述你要什么
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") id: Int): User
}
// 调用方:拿到就是解析好的对象
val user = api.getUser(1)
差别在哪?命令式把做什么和怎么做混在一起;声明式分离了意图和实现。
Retrofit 让你只声明"我要什么数据、从哪拿、怎么传参",底层的 URL 拼接、Header 注入、JSON 解析、线程调度全部封装掉。
这不仅是语法糖——它意味着你的网络层代码能够被静态分析、被 lint 检查、被编译期验证。你在 IDE 里写下 api.getUser("abc") 而接口声明的是 Int 时,编译器当场就报错。这在运行时拼 URL 的世界里是不可能的事。
1.2 关注点分离
Retrofit 把网络请求的职责拆成了三层:
| 层 | 职责 | 具体实现 |
|---|---|---|
| 接口声明层 | 定义 API 契约 | interface ApiService + 注解 |
| 适配层 | 把 Call 转成目标类型 | CallAdapter |
| 数据转换层 | JSON ↔ 对象 | Converter |
这三层各管各的,通过 Retrofit.Builder 装配。
Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(okHttpClient) // 网络执行层(OkHttp)
.addCallAdapterFactory(CoroutineCallAdapterFactory()) // 适配层
.addConverterFactory(GsonConverterFactory.create()) // 数据转换层
.build()
后面每一节都会深入这些组件的源码。
1.3 适配器模式贯穿始终
Retrofit 整个架构就是一套适配器模式的集大成者:
- CallAdapter:把
Call<R>适配成用户想要的东西(Observable<R>、Flow<R>、直接返回值) - Converter:把
ResponseBody适配成User,把User适配成RequestBody - 动态代理:本质也是一个适配器——把方法调用适配成 OkHttp Request
三个适配器层层嵌套:调用接口 → 动态代理 → OkHttp Request → CallAdapter → Converter
这种设计让 Retrofit 成为了 Android 生态中最可扩展的网络框架。想支持 Protobuf?加个 Converter。想返回 Flow?加个 CallAdapter。底层执行引擎想从 OkHttp 换成别的?也不是不行(虽然没人这么干)。
2. 动态代理核心
这是 Retrofit 最骚的部分。也是面试必考。
2.1 Java 动态代理原理
我们知道 Java 的 interface 没有实现类,无法直接 new。但动态代理可以在运行时凭空造出一个实现类,并把所有方法调用重定向到一个 InvocationHandler。
先看一个最简单的例子:
// 1. 定义接口
interface HelloService {
fun sayHello(name: String): String
}
// 2. InvocationHandler——所有方法调用的"入口"
val handler = InvocationHandler { proxy, method, args ->
println("方法被调用了:${method.name}")
when (method.name) {
"sayHello" -> "Hello, ${args?.get(0)}!"
"toString" -> "我是代理对象"
"hashCode" -> 42
else -> throw UnsupportedOperationException(method.name)
}
}
// 3. 创建代理
val proxy = Proxy.newProxyInstance(
HelloService::class.java.classLoader, // 类加载器
arrayOf(HelloService::class.java), // 要代理的接口
handler // 方法拦截器
) as HelloService
// 4. 使用
println(proxy.sayHello("千珏")) // → "Hello, 千珏!"
Proxy.newProxyInstance 干了两件事:
- 生成字节码:根据传入的接口,动态生成一个
$Proxy0类,它继承了Proxy并实现了所有接口 - 创建实例:new 一个
$Proxy0实例,传入InvocationHandler
生成的 $Proxy0.sayHello() 的实现大概长这样:
// 这是 JVM 动态生成的字节码的反编译结果
public final class $Proxy0 extends Proxy implements HelloService {
private static Method m1 = HelloService.class.getMethod("sayHello", String.class);
private static Method m0 = Object.class.getMethod("hashCode");
// ...更多 Method 对象
public String sayHello(String name) {
// 所有方法调用全部委托给 InvocationHandler
return (String) super.h.invoke(this, m1, new Object[]{name});
}
}
关键点:每一个接口方法对应的 Method 对象在静态初始化时就获取好了。这意味着 method.invoke() 的反射调用只发生一次(在 $Proxy0 的静态初始化块里),后续调用直接调用 InvocationHandler.invoke(),不需要再反射。
这也是 Retrofit 不需要 APT 就能高效工作的原因之一——代理对象的方法路由是纯虚方法分派,不是反射调用。
2.2 Retrofit.create() 源码拆解
有了上面的基础,看 Retrofit.create() 就简单了:
// Retrofit.java (简化)
public <T> T create(final Class<T> service) {
// 校验:必须是接口、不能扩展其他接口、不能是泛型参数
validateServiceInterface(service);
return (T) Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[]{service},
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// ★ 特殊处理 Object 方法
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
// ★ 特殊处理默认方法和 Kotlin 桥接方法
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// ★ 核心逻辑:加载 ServiceMethod 并执行
return loadServiceMethod(method).invoke(args);
}
}
);
}
这个 InvocationHandler 做了三件事:
- Object 方法直通:
equals()、hashCode()、toString()这些走默认实现,不进入 Retrofit 逻辑 - 默认方法处理:Java 8 接口默认方法和 Kotlin 桥接方法用
MethodHandle直接调用 - 核心路径:调用
loadServiceMethod(method).invoke(args)——解析方法、构造请求、执行
2.3 为什么用动态代理而不是 APT
这是一个面试高频问题。
APT(Annotation Processing Tool) :编译时扫描注解,生成 Java 代码。其他框架(如 Dagger、Room、Glide)都用 APT。
那 Retrofit 为啥不用?
| 维度 | 动态代理 | APT |
|---|---|---|
| 编译依赖 | 无 | 需要 annotationProcessor 配置 |
| 接口数量 | 多数 App 只有 1-5 个接口 | 不限 |
| 性能 | 每个方法调用拦截一次 InvocationHandler | 直接调用生成代码,无拦截 |
| 灵活性 | 同一接口可绑定不同 Retrofit 实例 | 编译时确定,不灵活 |
| 字节码体积 | 无生成文件 | 每个接口生成一个实现类 |
Retrofit 选择动态代理的原因很务实:
- 不增加编译步骤:引入依赖就完事,加 APT 要多配置
- 接口数量少:一个 App 的 API 接口通常不超过 5 个,反射开销可忽略
- 运行时灵活性:同一接口的不同实例可以连不同的 baseUrl,APT 做不到
- 框架简洁:不需要单独维护代码生成器
当然,也有追求极致零反射的方案——Square 的实验分支 retrofit-kotlin-compiler 就是 APT 方案(KSP),但一直没有合并到主分支。社区评价是"锦上添花,不是刚需"。
2.4 ServiceMethod 缓存
create() 里调用了 loadServiceMethod(method):
// Retrofit.java
private final Map<Method, ServiceMethod<?>> serviceMethodCache = new ConcurrentHashMap<>();
ServiceMethod<?> loadServiceMethod(Method method) {
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
关键设计:
- ConcurrentHashMap + synchronized 双重检查:高并发下只解析一次
- Method 对象作为 key:Method 的 identity 由声明类+方法名+参数类型唯一定义,天然不可变
- 解析是懒加载的:只有第一次调用时才解析,不浪费启动时间
对比用 APT 的框架(如 Room),Retrofit 的 ServiceMethod 相当于在运行时做了 APT 的事——解析注解、构建请求模板。只不过它只解析一次,缓存起来,后续调用只走 invoke()。
2.5 面试:调用接口方法时的完整调用链
api.getUser(1)
│
├─ 1. 动态代理捕获方法调用
│ Proxy.getUser() → InvocationHandler.invoke(proxy, method, args)
│
├─ 2. 加载 ServiceMethod(从缓存或新建)
│ loadServiceMethod(method) → ServiceMethod.parseAnnotations()
│ ├─ 解析方法注解(@GET、@POST、Headers)
│ ├─ 解析参数注解(@Path、@Query、@Body)
│ ├─ 选择 CallAdapter(返回类型适配器)
│ └─ 选择 Converter(请求/响应数据转换器)
│
├─ 3. 创建 OkHttpCall
│ ServiceMethod.invoke(args) → 创建 OkHttpCall(持有 RequestFactory)
│ └─ 如果是 suspend 函数,创建 SuspendForBody / SuspendForResponse
│
├─ 4. 发起请求
│ OkHttpCall.enqueue() / execute() → OkHttpClient.newCall(request)
│ └─ 经过 OkHttp 拦截器链 → 实际网络 I/O
│
└─ 5. 结果转换
OkHttp 响应 → Converter<ResponseBody, T>.convert()
→ 返回 User 对象 / 协程恢复
整条链路由三个核心对象串联起来:
ServiceMethod:元数据的化身,知道接口怎么调用、参数怎么传、结果怎么转。相当于接口的"反射描述"。OkHttpCall:真正的网络执行者,把 ServiceMethod 的元数据变成真正的 OkHttp 请求。它是Call<T>的实现类。CallAdapter:把OkHttpCall<T>(原始 Call)包装成用户想要的形式(suspend、Flow、RxJava)。
3. 注解解析
这节深入 ServiceMethod.parseAnnotations() 内部,看注解是怎么变成 OkHttp Request 的。
3.1 ServiceMethod.parseAnnotations()
// ServiceMethod.java (简化)
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
// 1. 解析方法级别的信息(@GET/POST、URL、Headers)
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
// 2. 获取方法的返回类型
Type returnType = method.getGenericReturnType();
// 3. 处理 Kotlin suspend 函数
// 如果最后一个参数是 Continuation,提取实际返回类型
if (Utils.hasUnresolvableType(returnType)) {
throw new IllegalArgumentException("...");
}
// 4. 找到合适的 CallAdapter
CallAdapter<T, ?> callAdapter = createCallAdapter(retrofit, method, returnType);
// 5. 找到合适的 Converter
Converter<ResponseBody, T> responseConverter = createResponseConverter(retrofit, method, returnType);
return new HttpServiceMethod<>(requestFactory, callAdapter, responseConverter);
}
}
解析分为两阶段:
阶段一:RequestFactory.parseAnnotations()——解析注解,产生一个"请求模板"。 阶段二:构建 CallAdapter 和 Converter——确定怎么执行和怎么转换。
3.2 RequestFactory——注解到请求模板
RequestFactory 是 Retrofit 把接口注解翻译成 OkHttp Request 的关键。
// RequestFactory.java (简化)
final class RequestFactory {
private final String httpMethod; // GET / POST / PUT / DELETE 等
private final String relativeUrl; // 相对路径,如 "users/{id}"
private final Headers headers; // 固定头部
private final MediaType contentType; // Content-Type
private final boolean hasBody; // 是否带请求体(POST/PUT)
private final ParameterHandler<?>[] parameterHandlers; // 参数处理器数组
// ★ 核心方法:构建 OkHttp Request
okhttp3.Request create(Object[] args) {
// 使用 RequestBuilder 构建器模式
RequestBuilder requestBuilder = new RequestBuilder(...);
// 遍历参数处理器,逐个添加参数
// parametersHandlers 在解析注解时就已经确定了
for (int i = 0; i < argumentCount; i++) {
parameterHandlers[i].apply(requestBuilder, args[i]);
}
return requestBuilder.build();
}
}
关键设计:RequestFactory 把"参数处理逻辑"抽象成了 ParameterHandler 对象数组。
每一个方法参数(比如 @Path("id") Int id)在解析时都被转换成了一个 ParameterHandler 实例。执行时只需要遍历数组执行 apply(),不需要再次解析注解。
3.3 方法注解解析
RequestFactory.parseAnnotations() 内部对 method 做了一轮反射遍历:
// RequestFactory.Builder.parseMethodAnnotations() (简化)
for (Annotation annotation : method.getAnnotations()) {
if (annotation instanceof GET) {
parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath("POST", ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath("PUT", ((PUT) annotation).value(), true);
} else if (annotation instanceof DELETE) {
parseHttpMethodAndPath("DELETE", ((DELETE) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath("HEAD", ((HEAD) annotation).value(), false);
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath("PATCH", ((PATCH) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath("OPTIONS", ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
parseHttpMethodAndPath(((HTTP) annotation).method(), ((HTTP) annotation).path(), ((HTTP) annotation).hasBody());
} else if (annotation instanceof Headers) {
parseHeaders(((Headers) annotation).value()); // 解析静态头部
} else if (annotation instanceof Multipart) {
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
isFormEncoded = true;
}
}
parseHttpMethodAndPath() 把 URL 模板中的路径参数({id})解析出来,但不是直接替换——它记录下占位符的位置和名称,在执行时才替换。
// parseHttpMethodAndPath 的核心逻辑
private void parseHttpMethodAndPath(String method, String path, boolean hasBody) {
this.httpMethod = method;
this.hasBody = hasBody;
this.relativeUrl = path;
// 解析 {param} 占位符
// 例如 "users/{id}/posts/{postId}" → 两个路径参数
Pattern PARAM_URL_REGEX = Pattern.compile("\{([a-zA-Z][a-zA-Z0-9_-]*)\}");
Matcher matcher = PARAM_URL_REGEX.matcher(path);
while (matcher.find()) {
String name = matcher.group(1);
// 检查是否已经有过这个参数名
if (gotPlaceholder(name)) {
throw methodError("URL "%s" has duplicate path parameter: %s", path, name);
}
gotPathParam(name);
}
// 验证路径不以 / 开头(由 baseUrl 处理)
// 验证路径参数数量一致
}
3.4 参数注解解析
每个方法参数可以有 0-2 个注解,RequestFactory.Builder 在 build() 时遍历参数:
// RequestFactory.Builder (简化)
for (int i = 0; i < method.getParameterTypes().length; i++) {
ParameterHandler<?> handler = null;
for (Annotation annotation : method.getParameterAnnotations()[i]) {
handler = parseParameter(handler, annotation, i);
}
if (handler == null) {
throw methodError("No Retrofit annotation found. (parameter #%d)", i);
}
parameterHandlers[i] = handler;
}
每个注解类型对应一个 ParameterHandler 子类:
// ParameterHandler 的子类体系
abstract class ParameterHandler<T> {
abstract void apply(RequestBuilder builder, T value) throws IOException;
// @Path
static final class Path<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
void apply(RequestBuilder builder, T value) {
builder.addPathParam(name, valueConverter.convert(value));
}
}
// @Query
static final class Query<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
void apply(RequestBuilder builder, T value) {
if (value != null) {
builder.addQueryParam(name, valueConverter.convert(value), encoded);
}
}
}
// @Body — 完全不同的逻辑
static final class Body<T> extends ParameterHandler<T> {
private final Converter<T, RequestBody> converter;
void apply(RequestBuilder builder, T value) {
if (value == null) {
throw new IllegalArgumentException("Body parameter value must not be null.");
}
builder.setBody(converter.convert(value));
}
}
// @Header
static final class Header<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
void apply(RequestBuilder builder, T value) {
if (value != null) {
builder.addHeader(name, valueConverter.convert(value));
}
}
}
// @Field (用于 FormUrlEncoded)
static final class Field<T> extends ParameterHandler<T> {
private final String name;
private final Converter<T, String> valueConverter;
private final boolean encoded;
void apply(RequestBuilder builder, T value) {
if (value != null) {
builder.addFormField(name, valueConverter.convert(value), encoded);
}
}
}
// @Part (用于 Multipart)
static final class Part<T> extends ParameterHandler<T> {
private final Headers headers;
private final Converter<T, RequestBody> converter;
void apply(RequestBuilder builder, T value) {
builder.addPart(headers, converter.convert(value));
}
}
}
可以看到 ParameterHandler 的职责极其单一:把一个参数值应用(apply)到 RequestBuilder 上。它不需要知道参数的来源,也不关心其他参数。
3.5 完整请求构建流程
当调用 api.getUser(1) 时,RequestFactory.create(args) 内部:
// RequestBuilder(内部类,构建 OkHttp Request)
final class RequestBuilder {
okhttp3.Request build() {
// 1. 拼接完整 URL
HttpUrl url = baseUrl.resolve(relativeUrl);
// 如果 URL 包含路径参数占位符 {id},
// 在 addPathParam() 时已经完成了替换
// 2. 设置方法 + 添加查询参数
// 这些是由 ParameterHandler.Query.apply() 添加的
// 3. 构建 Request
Request.Builder requestBuilder = new Request.Builder();
requestBuilder.url(url);
requestBuilder.method(httpMethod, body);
// 4. 添加 Header(来自 @Headers 和 @Header 参数)
for (Header header : headers) {
requestBuilder.addHeader(header.name, header.value);
}
return requestBuilder.build();
}
}
生成的一个实际的 OkHttp Request 大概长这样:
GET https://api.example.com/users/1?include_details=true HTTP/1.1
Authorization: Bearer xxxxx
Content-Type: application/json
整个过程没有反射调用——RequestFactory 在第一次调用时把所有注解解析成 ParameterHandler 数组,后续调用只是遍历数组执行 apply()。这是 Retrofit 高性能的秘密之一:运行时唯一的反射发生在 Method 获取和 InvocationHandler 调用上,而这两个在第一次调用后就缓存好了。
4. CallAdapter 机制
如果说动态代理和注解解析是 Retrofit 的骨架,那 CallAdapter 和 Converter 就是它的肌肉——决定了"怎么执行"和"怎么转换"。
4.1 CallAdapter 接口和作用
// CallAdapter.java
public interface CallAdapter<R, T> {
// 返回实际类型的 Type(用于 Converter 匹配)
Type responseType();
// ★ 核心方法:把 Call<R> 适配成 T
T adapt(Call<R> call);
// 工厂——Retrofit 通过工厂链匹配 CallAdapter
abstract class Factory {
// 根据返回类型和注解,返回匹配的 CallAdapter,或 null
public abstract @Nullable CallAdapter<?, ?> get(
Type returnType, Annotation[] annotations, Retrofit retrofit
);
// 工具方法:获取参数类型(如 Flow<User> → User)
protected static Type getParameterUpperBound(int index, ParameterizedType type) { ... }
protected static Class<?> getRawType(Type type) { ... }
}
}
responseType() 返回的是数据层的类型,不是用户层的类型。
举例来说:
| 方法签名 | 用户层返回类型 | responseType |
|---|---|---|
Call<User> getUser() | Call<User> | User |
Observable<User> getUser() | Observable<User> | User |
Flow<User> getUser() | Flow<User> | User |
User getUser() | User | User |
responseType 是 Converter 需要的——它要知道怎么反序列化响应体。CallAdapter 不关心这一点,它只知道要把 Call<R> 包装成什么类型。
4.2 Retrofit 如何选择 CallAdapter
// Retrofit.java (简化)
public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
return nextCallAdapter(null, returnType, annotations);
}
public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast,
Type returnType, Annotation[] annotations) {
// 遍历 callAdapterFactories 列表
int start = callAdapterFactories.indexOf(skipPast) + 1;
for (int i = start, count = callAdapterFactories.size(); i < count; i++) {
CallAdapter<?, ?> adapter = callAdapterFactories.get(i).get(returnType, annotations, this);
if (adapter != null) {
return adapter;
}
}
throw new IllegalArgumentException("... 没有匹配的 CallAdapter");
}
当 createCallAdapter() 返回类型后,框架会用这个 responseType 去找匹配的 Converter<ResponseBody, R>。
4.3 DefaultCallAdapterFactory——Android 平台的关键
DefaultCallAdapterFactory 是 Retrofit 默认的 CallAdapter 工厂,负责处理返回类型为 Call<T> 的情况。但 Android 平台上其实不是它——是 Platform 里的内部实现。
// Platform.java——根据平台自动注入默认 CallAdapter
class Platform {
static Platform get() {
return PLATFORM; // 自动检测:Android、Java 8 或 Java 9+
}
// Android 平台的 CallAdapter
static final class Android extends Platform {
@Override
List<? extends CallAdapter.Factory> defaultCallAdapterFactories(
@Nullable Executor callbackExecutor) {
// Android 平台的默认 CallAdapter
DefaultCallAdapterFactory executorFactory =
new DefaultCallAdapterFactory(callbackExecutor);
return Collections.singletonList(executorFactory);
}
@Override
Executor defaultCallbackExecutor() {
// ★ Android 特有的主线程调度
// 通过 Handler 把回调投递到主线程 Looper
return new Executor() {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
}
}
DefaultCallAdapterFactory 的实现:
// DefaultCallAdapterFactory.java
final class DefaultCallAdapterFactory extends CallAdapter.Factory {
private final @Nullable Executor callbackExecutor;
@Override
public @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
// 只处理 Call<T> 类型
if (getRawType(returnType) != Call.class) {
return null;
}
// 提取 Call<T> 中的 T
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override
public Type responseType() {
return responseType;
}
@Override
public Call<Object> adapt(Call<Object> call) {
// ★ 把原始 Call 包装成 ExecutorCallbackCall
// ExecutorCallbackCall 保证 enqueue 的回调在主线程执行
if (callbackExecutor != null) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
return call;
}
};
}
}
ExecutorCallbackCall 是关键——它把 enqueue() 的回调通过 Handler 投递到主线程,这就是为什么 Android 上 Retrofit 的回调默认在主线程执行。
// ExecutorCallbackCall.java (简化)
static final class ExecutorCallbackCall<T> implements Call<T> {
final Executor callbackExecutor;
final Call<T> delegate; // 真正的 OkHttpCall
@Override
public void enqueue(final Callback<T> callback) {
delegate.enqueue(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
// 通过 callbackExecutor(主线程 Handler)执行回调
callbackExecutor.execute(() -> {
if (delegate.isCanceled()) {
callback.onFailure(ExecutorCallbackCall.this, new IOException("Canceled"));
} else {
callback.onResponse(ExecutorCallbackCall.this, response);
}
});
}
@Override
public void onFailure(Call<T> call, Throwable t) {
callbackExecutor.execute(() -> callback.onFailure(ExecutorCallbackCall.this, t));
}
});
}
@Override
public Response<T> execute() throws IOException {
// execute 不涉及回调,不包装
return delegate.execute();
}
}
4.4 协程 suspend 适配(HttpServiceMethod)
当方法返回类型是 suspend 函数时,标准的 CallAdapter 工厂匹配不到,因为返回类型不是 Call<T> 而是 Object(suspend 函数编译后返回 Object,最后一个参数是 Continuation)。
这是 Retrofit 对 suspend 函数的特殊处理——不在 CallAdapter 层面,而在 HttpServiceMethod 层面。
// HttpServiceMethod.java (简化)
abstract class HttpServiceMethod<ResponseT, ReturnT> extends ServiceMethod<ReturnT> {
@Override
ReturnT invoke(Object[] args) {
// 构建 OkHttpCall
OkHttpCall<ResponseT> call = new OkHttpCall<>(requestFactory, responseConverter);
// 调用子类的 adapt() 方法
return adapt(call, args);
}
// 抽象方法:由子类实现不同的适配逻辑
protected abstract ReturnT adapt(OkHttpCall<ResponseT> call, Object[] args);
}
当方法返回类型检测到 Continuation 参数时,Retrofit 创建的不是普通的 CallAdapted 子类,而是 SuspendForBody 或 SuspendForResponse:
// HttpServiceMethod.java 内部的工厂方法
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> create(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 判断是否是 suspend 函数
boolean continuation = false;
Type[] parameterTypes = method.getGenericParameterTypes();
Class<?>[] parameterAnnotationsArray = ...;
// 检查最后一个参数是否是 Continuation
int parameterCount = parameterTypes.length;
if (parameterCount > 0) {
Type lastParamType = parameterTypes[parameterCount - 1];
if (lastParamType instanceof ParameterizedType
&& ((ParameterizedType) lastParamType).getRawType() == Continuation.class) {
continuation = true;
}
}
if (continuation) {
// 如果方法声明了一个 Kotlin 的 suspend 函数
// 且最后一个参数是 Continuation 类型
// 判断是否需要 awaitResponse(返回 Response<T> 而不是 T)
boolean isResponse = getRawType(returnType) == Response.class;
if (isResponse) {
return new SuspendForResponse<>(...);
} else {
return new SuspendForBody<>(...);
}
}
// 非 suspend 函数走正常的 CallAdapter
CallAdapter<ResponseT, ReturnT> callAdapter = ...;
return new CallAdapted<>(..., callAdapter);
}
SuspendForBody——最常用的实现
// HttpServiceMethod.java 内部
static final class SuspendForBody<ResponseT> extends HttpServiceMethod<ResponseT, Object> {
private final Converter<ResponseBody, ResponseT> responseConverter;
@Override
protected Object adapt(OkHttpCall<ResponseT> call, Object[] args) {
// 取出 Continuation(Call<ResponseT> 中的最后一个参数)
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
// ★ 核心:使用 suspendCancellableCoroutine 桥接回调
return KotlinExtensions.awaitBody(call, continuation);
}
}
// KotlinExtensions.kt
suspend fun <T> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
val body = response.body()
if (body == null) {
// 返回 null 的情况(如 204 No Content)
continuation.resume(body)
} else {
continuation.resume(body)
}
} else {
// HTTP 错误(4xx, 5xx)
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
// 网络错误(IO异常、超时等)
continuation.resumeWithException(t)
}
})
// 协程取消时取消请求
continuation.invokeOnCancellation {
call.cancel()
}
}
}
KotlinExtensions源码
Retrofit 还提供了两个 Kotlin 扩展,更好地解释了 await() vs awaitResponse():
// KotlinExtensions.kt
// 直接返回反序列化后的 body
suspend fun <T> Call<T>.await(): T {
return awaitResponse().body()!!
}
// 返回包含状态码的 Reponse<T>
suspend fun <T> Call<T>.awaitResponse(): Response<T> {
return suspendCancellableCoroutine { continuation ->
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
continuation.resume(response)
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
continuation.invokeOnCancellation {
call.cancel()
}
}
}
区别:
| 方法 | 返回 | HTTP 错误 | 网络错误 | 空 body |
|---|---|---|---|---|
await() / awaitBody() | T | 抛 HttpException | 抛异常 | 返回 null(204) |
awaitResponse() | Response<T> | 正常返回,不抛 | 抛异常 | 正常返回 |
4.4 自定义 CallAdapter 实战
将 Call<T> 包装为 Call<ApiResult<T>>,统一处理错误:
sealed class ApiResult<out T> {
data class Success<T>(val data: T) : ApiResult<T>()
data class HttpError(val code: Int, val message: String) : ApiResult<Nothing>()
data class NetworkError(val exception: IOException) : ApiResult<Nothing>()
}
class ApiResultCall<T>(private val delegate: Call<T>) : Call<ApiResult<T>> {
override fun enqueue(callback: Callback<ApiResult<T>>) {
delegate.enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val result = if (response.isSuccessful) {
val body = response.body()
if (body != null) ApiResult.Success(body)
else ApiResult.HttpError(response.code(), "Empty body")
} else {
ApiResult.HttpError(response.code(), response.message())
}
callback.onResponse(this@ApiResultCall, Response.success(result))
}
override fun onFailure(call: Call<T>, t: Throwable) {
val result = if (t is IOException) {
ApiResult.NetworkError(t)
} else {
ApiResult.NetworkError(IOException(t))
}
callback.onResponse(this@ApiResultCall, Response.success(result))
}
})
}
override fun clone() = ApiResultCall(delegate.clone())
override fun execute(): Response<ApiResult<T>> = throw UnsupportedOperationException()
override fun isExecuted() = delegate.isExecuted
override fun cancel() = delegate.cancel()
override fun isCanceled() = delegate.isCanceled
override fun request() = delegate.request()
override fun timeout() = delegate.timeout()
}
class ApiResultCallAdapterFactory : CallAdapter.Factory() {
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
if (getRawType(returnType) != Call::class.java) return null
val responseType = getParameterUpperBound(0, returnType as ParameterizedType)
if (getRawType(responseType) != ApiResult::class.java) return null
val dataType = getParameterUpperBound(0, responseType as ParameterizedType)
return object : CallAdapter<Any, Call<ApiResult<Any>>> {
override fun responseType() = dataType
override fun adapt(call: Call<Any>) = ApiResultCall(call)
}
}
}
5. Converter 机制
5.1 Converter 接口
interface Converter<F, T> {
fun convert(value: F): T?
}
abstract class Factory {
open fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? = null
open fun requestBodyConverter(type: Type, paramAnnotations: Array<Annotation>, methodAnnotations: Array<Annotation>, retrofit: Retrofit): Converter<*, RequestBody>? = null
open fun stringConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<*, String>? = null
}
5.2 GsonConverterFactory 源码解析
class GsonResponseBodyConverter<T>(
private val gson: Gson,
private val adapter: TypeAdapter<T>
) : Converter<ResponseBody, T> {
override fun convert(value: ResponseBody): T? {
val reader = gson.newJsonReader(value.charStream())
return value.use {
val result = adapter.read(reader)
if (!reader.peek().equals(JsonToken.END_DOCUMENT)) {
throw JsonIOException("JSON document was not fully consumed.")
}
result
}
}
}
5.3 序列化方案对比
| 维度 | Gson | Moshi | kotlinx.serialization |
|---|---|---|---|
| Kotlin 支持 | 一般 | 好(codegen) | 原生 |
| null 安全 | ⚠️ 可能赋 null | ✅ 严格 | ✅ 严格 |
| 默认值 | ❌ 忽略 | ✅ 支持 | ✅ 支持 |
| 反射依赖 | 是 | 可选 | 无 |
| 多平台 | ❌ | ❌ | ✅ KMP |
| 包大小 | ~250KB | ~150KB | ~300KB |
选型:新项目用 kotlinx.serialization;存量项目 Moshi codegen 是最佳升级路径。
5.4 自定义 Converter:拆包 BaseResponse
data class BaseResponse<T>(val code: Int, val message: String, val data: T?)
class UnwrapConverterFactory(private val inner: Converter.Factory) : Converter.Factory() {
override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *>? {
val wrappedType = TypeToken.getParameterized(BaseResponse::class.java, type).type
val delegate = inner.responseBodyConverter(wrappedType, annotations, retrofit) ?: return null
@Suppress("UNCHECKED_CAST")
return Converter<ResponseBody, Any> { body ->
val base = (delegate as Converter<ResponseBody, BaseResponse<Any>>).convert(body)
if (base?.code != 0) throw ApiException(base?.code ?: -1, base?.message ?: "Unknown")
base.data
}
}
}
6. 协程与 Flow 集成
6.1 suspend 函数支持原理
suspend fun <T> Call<T>.await(): T {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation { cancel() }
enqueue(object : Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
continuation.resume(response.body()!!)
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
6.2 Flow 集成
// 分页
fun getPagedUsers(): Flow<List<User>> = flow {
var page = 1
while (true) {
val users = api.getUsers(page = page, size = 20)
if (users.isEmpty()) break
emit(users)
page++
}
}
// 轮询
fun pollOrderStatus(orderId: String): Flow<OrderStatus> = flow {
while (true) {
emit(api.getOrderStatus(orderId))
delay(3000)
}
}.distinctUntilChanged()
6.3 错误处理
suspend fun <T> safeCall(block: suspend () -> T): ApiResult<T> {
return try {
ApiResult.Success(block())
} catch (e: HttpException) {
ApiResult.HttpError(e.code(), e.message())
} catch (e: IOException) {
ApiResult.NetworkError(e)
}
}
7. 实战最佳实践
7.1 Token 刷新拦截器
class TokenRefreshInterceptor(private val tokenProvider: TokenProvider) : Interceptor {
private val lock = Any()
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.header("Authorization", "Bearer ${tokenProvider.accessToken}")
.build()
val response = chain.proceed(request)
if (response.code != 401) return response
response.close()
synchronized(lock) {
val currentToken = tokenProvider.accessToken
if (currentToken != request.header("Authorization")?.removePrefix("Bearer ")) {
return chain.proceed(request.newBuilder()
.header("Authorization", "Bearer $currentToken").build())
}
if (!tokenProvider.refreshToken()) {
tokenProvider.logout()
throw TokenExpiredException("Token refresh failed")
}
}
return chain.proceed(request.newBuilder()
.header("Authorization", "Bearer ${tokenProvider.accessToken}").build())
}
}
7.2 MockWebServer 测试
class UserApiTest {
private val server = MockWebServer()
private lateinit var api: UserApi
@Before fun setup() {
server.start()
api = Retrofit.Builder().baseUrl(server.url("/"))
.addConverterFactory(GsonConverterFactory.create())
.build().create(UserApi::class.java)
}
@After fun tearDown() = server.shutdown()
@Test fun `getUser returns parsed user`() = runTest {
server.enqueue(MockResponse().setBody("""{ "id": 42, "name": "千寻" }""")
.addHeader("Content-Type", "application/json"))
val user = api.getUser(42)
assertEquals(42, user.id)
val recorded = server.takeRequest()
assertEquals("/users/42", recorded.path)
}
}
8. 总结
面试高频题
Q:Retrofit.create() 做了什么? A:通过 Java 动态代理创建接口实现类。调用方法时解析注解构建 ServiceMethod(缓存在 ConcurrentHashMap),创建 OkHttpCall 并通过 CallAdapter 适配返回类型。
Q:suspend 函数如何被 Retrofit 支持? A:不是通过 CallAdapter。HttpServiceMethod.parseAnnotations() 检测到 Continuation 参数时使用 SuspendForBody/SuspendForResponse 子类,内部通过 KotlinExtensions.await() 用 suspendCancellableCoroutine 桥接回调。
Q:Converter 的调用时机? A:请求时 requestBodyConverter 将 @Body 序列化为 RequestBody;响应时 responseBodyConverter 将 ResponseBody 反序列化为目标类型。按注册顺序遍历,第一个非 null 生效。
Q:Retrofit 和 OkHttp 的关系? A:Retrofit 是上层封装,负责接口定义、注解解析、类型转换;OkHttp 负责实际 HTTP 通信。Retrofit 最终把每个调用转成 OkHttpCall 委托给 OkHttpClient 执行。
Q:为什么 Token 刷新用 synchronized 而不用 Mutex? A:OkHttp 拦截器运行在线程池普通线程中。Mutex 需要 runBlocking 桥接,线程池耗尽时可能死锁。synchronized 在此场景更安全。
本文代码基于 Retrofit 2.9.x / OkHttp 4.x / Kotlin Coroutines 1.7.x,均已简化保留核心逻辑。