深入浅出安卓OkHttp源码机制

136 阅读4分钟

深入浅出安卓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 ←

内置拦截器

  1. RetryAndFollowUpInterceptor:负责重试和重定向
  2. BridgeInterceptor:补全请求头(如Content-Type)
  3. CacheInterceptor:缓存管理
  4. ConnectInterceptor:建立连接
  5. CallServerInterceptor:最终发送请求

4. 连接机制(HTTP/2魔法)

优势

  • 多路复用:一个连接并发多个请求
  • 头部压缩:减少传输量
  • 服务器推送:快递员主动送货

源码关键点

// RealConnection.java
public void connect(...) {
    if (protocol == Protocol.HTTP_2) {
        startHttp2Connection();
    } else {
        startHttp1Connection();
    }
}

5. 缓存控制(CacheInterceptor) - 智能仓库

工作逻辑

  1. 检查是否有缓存
  2. 如果有且未过期 → 直接返回
  3. 如果过期 → 发请求验证是否需要更新

源码亮点

// 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源码学习路线

  1. 入口RealCall.enqueue()
  2. 核心流程:拦截器链RealInterceptorChain.proceed()
  3. 连接管理RealConnection.connect()
  4. 线程调度Dispatcher.enqueue()
  5. 缓存机制CacheInterceptor.intercept()

九、总结

OkHttp的优秀设计:

  • 高效:连接池+线程池复用
  • 灵活:拦截器可扩展
  • 可靠:自动重试机制
  • 现代:支持HTTP/2

记住三个关键:

  1. 拦截器链是核心处理机制
  2. 连接池是性能关键
  3. Dispatcher是调度中心

就像优秀的快递公司需要好的管理,OkHttp的成功源于精妙的设计。理解它的源码,你就能更好地驾驭这个网络请求利器!