深入浅出安卓OkHttp源码机制
一、OkHttp是什么?它像什么?
想象OkHttp就像是一个超级快递员团队,专门帮你收发网络包裹(HTTP请求)。它比系统自带的HttpURLConnection更聪明:
- 自动管理连接池(快递员休息站)
- 支持HTTP/2(多件包裹一起送)
- 有拦截器机制(包裹检查站)
- 自动重试失败请求(快递员很执着)
二、核心工作流程(快递公司运作图)
1. 客户下单(创建请求)
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
2. 快递员接单(创建Call对象)
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
3. 派送包裹(同步/异步执行)
// 同步方式(快递员等你签收)
Response response = call.execute();
// 异步方式(快递员送到后通知你)
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
// 处理响应
}
});
三、五大核心组件源码解析
1. 调度器(Dispatcher) - 快递站长
职责:
- 管理异步请求队列
- 控制最大并发数(默认64)
- 复用空闲快递员(线程)
关键源码:
// Dispatcher.java
public synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests) {
// 有空闲快递员,直接派单
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
// 没有就放进等待区
readyAsyncCalls.add(call);
}
}
2. 连接池(ConnectionPool) - 快递员休息站
黑科技:
- 默认维护5个空闲连接(快递员)
- 每个连接最多空闲5分钟
- 自动清理闲置连接
省流量原理:
// ConnectionPool.java
boolean cleanup(long now) {
// 遍历所有连接,清理超时的
if (idleDurationNs >= IDLE_CONNECTION_TIMEOUT_NS) {
connections.remove(connection);
}
}
3. 拦截器链(Interceptor Chain) - 包裹安检流水线
工作流程: 请求 → 拦截器1 → 拦截器2 → ... → 服务器 响应 ← 拦截器N ← ... ← 拦截器1 ←
内置拦截器:
- RetryAndFollowUpInterceptor:负责重试和重定向
- BridgeInterceptor:补全请求头(如Content-Type)
- CacheInterceptor:缓存管理
- ConnectInterceptor:建立连接
- CallServerInterceptor:最终发送请求
4. 连接机制(HTTP/2魔法)
优势:
- 多路复用:一个连接并发多个请求
- 头部压缩:减少传输量
- 服务器推送:快递员主动送货
源码关键点:
// RealConnection.java
public void connect(...) {
if (protocol == Protocol.HTTP_2) {
startHttp2Connection();
} else {
startHttp1Connection();
}
}
5. 缓存控制(CacheInterceptor) - 智能仓库
工作逻辑:
- 检查是否有缓存
- 如果有且未过期 → 直接返回
- 如果过期 → 发请求验证是否需要更新
源码亮点:
// CacheInterceptor.java
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
四、OkHttp的三大设计模式
1. 责任链模式(拦截器)
每个拦截器只处理自己关心的部分,不关心其他环节
2. 外观模式(OkHttpClient)
复杂功能简单化,统一入口
3. 享元模式(连接池)
重复利用TCP连接,减少创建开销
五、性能优化关键点
1. 单例模式使用OkHttpClient
// 正确做法(全局共用)
OkHttpClient client = new OkHttpClient();
// 错误做法(每次新建)
OkHttpClient client = new OkHttpClient(); // 每次创建消耗资源
2. 合理设置超时时间
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build();
3. 启用响应缓存
File cacheDir = new File(context.getCacheDir(), "okhttp-cache");
Cache cache = new Cache(cacheDir, 10 * 1024 * 1024); // 10MB
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
六、常见问题排查指南
1. 请求卡住不返回
- 检查是否忘记关闭ResponseBody
- 查看拦截器是否有阻塞操作
- 用
client.eventListener()监控请求生命周期
2. 内存泄漏
- 确保Callback不使用Activity引用
- 使用静态内部类或弱引用
3. HTTPS证书问题
// 信任所有证书(仅调试用)
OkHttpClient client = new OkHttpClient.Builder()
.hostnameVerifier((hostname, session) -> true)
.sslSocketFactory(insecureSocketFactory(), trustAllCerts())
.build();
七、高级特性:自定义拦截器
1. 日志拦截器
public class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.nanoTime();
Log.d("OKHTTP", String.format("发送请求 %s", request.url()));
Response response = chain.proceed(request);
long endTime = System.nanoTime();
Log.d("OKHTTP", String.format("收到响应 [%s] %.1fms",
response.code(), (endTime - startTime) / 1e6d));
return response;
}
}
2. 统一添加请求头
public class AuthInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", "Bearer " + token)
.build();
return chain.proceed(request);
}
}
八、OkHttp源码学习路线
- 入口:
RealCall.enqueue() - 核心流程:拦截器链
RealInterceptorChain.proceed() - 连接管理:
RealConnection.connect() - 线程调度:
Dispatcher.enqueue() - 缓存机制:
CacheInterceptor.intercept()
九、总结
OkHttp的优秀设计:
- 高效:连接池+线程池复用
- 灵活:拦截器可扩展
- 可靠:自动重试机制
- 现代:支持HTTP/2
记住三个关键:
- 拦截器链是核心处理机制
- 连接池是性能关键
- Dispatcher是调度中心
就像优秀的快递公司需要好的管理,OkHttp的成功源于精妙的设计。理解它的源码,你就能更好地驾驭这个网络请求利器!