Android OkHttp框架全解析

在 Android 客户端开发中,网络请求是核心能力之一。从早期的HttpURLConnection到如今的 OkHttp,网络框架的演进始终围绕「简洁、高效、稳定」展开。OkHttp 作为 Square 公司开源的轻量级网络框架,不仅成为 Android 官方推荐的网络请求方案,更是 Retrofit、Volley、Glide 等框架的底层依赖。

一、OkHttp是什么

OkHttp 是由 Square 公司开源的一个 高性能 HTTP 客户端框架,主要用于 Android 和 Java/Kotlin 客户端进行网络请求。

发展背景

  • 替代 Android 原生HttpURLConnection:原生 API 设计繁琐、性能差、缺乏异步支持,OkHttp 通过简洁的 API 和优化的底层实现解决了这些痛点;
  • 由 Square 公司开发(同公司还出品 Retrofit、LeakCanary),Retrofit 底层完全基于 OkHttp 实现,是目前 Android 生态的事实标准;
  • 最新稳定版:OkHttp 4.x(全面支持 Kotlin,兼容 Java)。

二、OkHttp核心用途

OkHttp 几乎覆盖客户端所有网络请求场景,核心用途包括:

  1. 基础 HTTP 请求:GET/POST/PUT/DELETE 等 RESTful API 调用;
  2. 复杂请求:文件上传(单文件 / 多文件)、文件下载(断点续传);
  3. 高级特性:请求 / 响应拦截(日志、Token 刷新、加解密)、缓存控制、超时配置;
  4. 连接优化:连接池复用、自动重连、HTTPS 证书配置;
  5. 异步请求:非阻塞式网络调用,避免主线程阻塞。

三、OkHttp基本用法

了解OkHttp基本用法之前,我们来看看OkHttp中的核心组件:

|--------------|---------------------------------------|
| 组件名称 | 作用 |
| OkHttpClient | 配置中心。持有共享状态(如连接池、缓存、代理等)。建议全局单例。 |
| Request | 封装用户的请求信息;URL、方法(GET/POST)、请求头、请求体。 |
| Response | 封装服务器返回的数据;状态码、响应头、响应体。 |
| Call | 具体的请求任务。分为同步execute()和异步enqueue() |
| Dispatcher | 调度器。决定异步请求何时执行,管理线程池。 |

环境配置

首先在 Android 项目的build.gradle(Module 级别)中引入依赖:

XML 复制代码
// OkHttp核心依赖
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
// 可选:OkHttp日志拦截器(调试用)
implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'

AndroidManifest.xml 中需添加网络权限:

XML 复制代码
<uses-permission android:name="android.permission.INTERNET" />
<!-- Android 9.0+需配置cleartextTrafficPermitted(允许HTTP明文请求) -->
<application
    ...
    android:usesCleartextTraffic="true">
</application>

示例代码

设置 OkHttpClient 配置

java 复制代码
File cacheDirectory = new File(context.getCacheDir(), "http_cache");
Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10MB 缓存

OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(15, TimeUnit.SECONDS) // 连接超时
        .readTimeout(20, TimeUnit.SECONDS)    // 读取超时
        .writeTimeout(20, TimeUnit.SECONDS)   // 写入超时
        .cache(cache)                         // 开启缓存
        .retryOnConnectionFailure(true)       // 失败自动重连
        .build();

异步GET请求:这是最常用的方式,通过 enqueue 将请求交给 Dispatcher 调度,不会阻塞主线程。

java 复制代码
// 1. 创建全局共享的 OkHttpClient 实例
OkHttpClient client = new OkHttpClient();

// 2. 构造请求任务 (Request)
Request request = new Request.Builder()
        .url("https://api.github.com/users/google")
        .build();

// 3. 发起异步请求 (Call)
client.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        e.printStackTrace(); // 处理失败情况
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        // 4. 处理响应 (Response)
        if (response.isSuccessful()) {
            String body = response.body().string();
            System.out.println(body);
        }
    }
});

POST 提交 JSON 数据

java 复制代码
public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

// 1. 准备 JSON 字符串
String json = "{\"name\":\"Gemini\", \"message\":\"Hello OkHttp\"}";

// 2. 创建 RequestBody
RequestBody body = RequestBody.create(json, JSON);

// 3. 构造 POST 请求
Request request = new Request.Builder()
        .url("https://example.com/api/post")
        .post(body)
        .build();

// 4. 执行请求
try (Response response = client.newCall(request).execute()) { // 这里演示同步请求 execute()
    System.out.println(response.body().string());
} catch (IOException e) {
    e.printStackTrace();
}

四、拦截器机制

OkHttp 的拦截器机制基于责任链模式设计,当你发起一个请求时,这个请求会像流水线上的零件一样,依次经过多个工位的处理。

OkHttp 将拦截器分为两类,核心区别在于执行时机和作用范围:

|--------|-------------------|-------------------------|
| 特性 | 应用拦截器 | 网络拦截器 |
| 注册方式 | addInterceptor() | addNetworkInterceptor() |
| 执行时机 | 仅在请求发起时执行 1 次 | 每次网络请求(含重定向、重试)都执行 |
| 是否命中缓存 | 是 | 否 |
| 关注点 | 原始请求和最终结果,不关心中间过程 | 关心网络上的"真实"数据流(如 Header) |
| 用途 | 统一添加请求头、打印业务级日志 | 监控网络层耗时、抓包、修改网络请求参数 |

OkHttp 自带了五个内置拦截器:

  • RetryAndFollowUpInterceptor:负责请求的重试和重定向(比如 3xx 状态码的重定向);
  • BridgeInterceptor:"桥接" 用户请求和网络请求 ------ 把你构建的Request转为符合 HTTP 规范的请求(比如加默认的User-Agent、处理 Cookie、编码 POST 体等),并把响应转为Response
  • CacheInterceptor:处理缓存逻辑 ------ 判断请求是否命中缓存,命中则直接返回缓存响应,未命中则继续,响应返回后更新缓存;
  • ConnectInterceptor:建立与服务器的连接(TCP/HTTPS),获取RealConnection
  • CallServerInterceptor:最终的 "执行者"------ 向服务器发送请求数据、读取响应数据,是唯一真正和服务器交互的拦截器。

自定义拦截器实现:拦截器的核心是实现Interceptor接口,重写intercept(Chain chain)方法,其中Chain是拦截器链的核心对象,你需要通过chain.proceed(request)触发后续拦截器的执行。

java 复制代码
// 自定义一个拦截器
class HeaderInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request originalRequest = chain.request();
        
        // 在拦截器中修改请求:添加统一的 Header
        Request newRequest = originalRequest.newBuilder()
                .header("Authorization", "Bearer your_token_here")
                .header("User-Agent", "OkHttp-Example-App")
                .build();
        
        // 把修改后的请求继续传递下去
        return chain.proceed(newRequest);
    }
}

// 在配置 Client 时注入拦截器
OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(new HeaderInterceptor()) // 添加到应用拦截器层
        .build();

五、内置的线程池与调度器

在 OkHttp 中,Dispatcher(调度器**)** 和 线程池 是支撑高并发请求的核心。

Dispatcher

Dispatcher 的核心职责是:定义任务的执行策略。它并不直接处理网络流,而是决定哪些请求可以立即执行,哪些需要排队等待。

Dispatcher 内部维护了三个任务队列(双端):

  • readyAsyncCalls:准备就绪的异步请求队列。当并发数达到上限时,请求会暂存到这里。

  • runningAsyncCalls:正在执行的异步请求队列(包括正在读写数据的请求)。

  • runningSyncCalls:正在执行的同步请求队列。

并发阈值(默认配置)

OkHttp 对并发做了精细限制,以防止耗尽系统资源:

  • maxRequests = 64:全网域名下,最大同时并发请求数为 64。

  • maxRequestsPerHost = 5:单个主机(Host)下,最大并发请求数为 5。

线程池

OkHttp 内部只使用了一个线程池。其构造参数非常有讲究:

java 复制代码
public synchronized ExecutorService executorService() {
    if (executorService == null) {
        executorService = new ThreadPoolExecutor(
            0,                        // corePoolSize: 核心线程数
            Integer.MAX_VALUE,        // maximumPoolSize: 最大线程数
            60, TimeUnit.SECONDS,     // keepAliveTime: 闲置存活时间
            new SynchronousQueue<>(), // workQueue: 阻塞队列
            Util.threadFactory("OkHttp Dispatcher", false)
        );
    }
    return executorService;
}

OkHttp 的默认线程池本质是CachedThreadPool(缓存线程池),适配 HTTP 异步请求的核心特点:

  • 核心线程数 = 0:避免空闲线程长期占用内存(HTTP 请求是短任务,执行完即释放);
  • 最大线程数 = Integer.MAX_VALUE:理论上支持无限并发(实际由 Dispatcher 的maxRequests限制,避免资源耗尽);
  • 空闲线程存活 60 秒:复用近期的空闲线程,减少线程创建 / 销毁的开销;
  • SynchronousQueue 同步队列:无缓冲队列,提交的任务直接分配给线程执行(无排队,适配 Dispatcher 的就绪队列);
  • 守护线程:线程池线程不会阻止 JVM 退出(比如 App 退出时,无需手动关闭线程池)。

OkHttp 通过 Dispatcher 统一管理同步和异步请求,并在其内部实现全局和单 Host 的并发控制;真正的执行交给一个基于 SynchronousQueue(同步队列) 的 CachedThreadPool,从而实现高并发、可控、可回收的 IO 线程模型。

六、连接池复用机制

OkHttp 连接池复用机制的核心是用双端队列存储空闲 TCP 连接,按需复用、定时清理。

OkHttp 的连接池复用机制是其性能优于普通 URLConnection 的核心原因。在网络请求中,建立连接的成本非常高,TCP 需要三次握手,TLS/SSL 需要四次握手,如果每次发请求都重新建立连接,大量时间就浪费在握手/挥手,请求延迟高、性能差,OkHttp 的目标就是:只要能用旧的 Socket,绝不建新的。

OkHttp 使用 ConnectionPool 类来管理连接。它的内部结构非常简单,核心是一个双端队列:

java 复制代码
// 存放所有连接(包括空闲的和正在使用的)
private final Deque<RealConnection> connections = new ArrayDeque<>();

这个池子默认的配置是:

  • 最大空闲连接数 (Max Idle Connections):5 个。

  • 连接保持存活时间 (Keep-Alive Duration):5 分钟。

复用前提:两个请求的地址、协议、HTTPS配置都相同,且连接未过期。

复用查找流程

ConnectInterceptor 开始工作时,它会去连接池里"捞人":

  1. 遍历连接池 :遍历 connections 队列中的每一个 RealConnection

  2. 资格检查 (isEligible)

    • 检查连接的 Address 是否与当前请求的 Address 匹配。

    • 检查连接是否已达到负载上限(HTTP/1.1 为 1,HTTP/2 默认 Integer.MAX)。

  3. 多路复用检查 (HTTP/2 特权)

    • 如果是 HTTP/2,只要 IP 地址和端口对得上,且证书匹配(即使域名不同,只要证书覆盖了新域名),就可以合并复用同一个连接(Connection Coalescing)。
  4. 返回连接

    • 如果找到合适的,直接返回该 RealConnection

    • 如果没找到,创建一个新的连接,进行 TCP/TLS 握手,然后放入池中。

自动清理机制

连接池不会无限存储空闲连接,CleanupRunnable 后台线程会定期执行清理逻辑,规则如下:

  1. 遍历连接池中的所有空闲连接,检查「最后使用时间」:超过 5 分钟 → 关闭并移除;
  2. 如果空闲连接数超过 5 个 → 关闭最久未使用的连接;
  3. 清理完成后,计算下一次清理的时间(比如有连接还剩 2 分钟过期,就 2 分钟后再清理);
  4. 整个清理过程是「懒加载」的:只有当有新连接放入池、或有请求尝试复用连接时,才触发清理检查,避免空耗 CPU。

七、OkHttp核心优势

对比 Android 原生HttpURLConnection和早期的 Volley,OkHttp 的优势体现在以下 6 点:

1. 简洁易用的 API

无需繁琐的流处理、参数拼接,一行代码构建请求,回调式异步处理,大幅降低开发成本。

2. 异步非阻塞设计

基于线程池实现异步请求,避免主线程阻塞,回调方法自动运行在子线程,开发者只需关注业务逻辑。

3. 连接池复用(性能核心)

OkHttp 维护一个 HTTP 连接池(ConnectionPool),默认最多保持 5 个空闲连接,超时时间 5 分钟。复用连接避免了频繁创建 / 销毁 TCP 连接的开销(TCP 三次握手 / 四次挥手),大幅提升请求效率。

4. 强大的拦截器机制

拦截器(Interceptor)是 OkHttp 的灵魂,支持在请求发送前、响应返回后插入自定义逻辑。

5. 智能缓存策略

支持基于 HTTP 缓存规则(Cache-ControlETag)的本地缓存,可配置缓存目录和大小,离线时可读取缓存数据,减少网络请求。

6. 高稳定性

  • 自动重连:网络波动时自动重试;
  • 自动重定向:支持 3xx 状态码的重定向;
  • HTTPS 支持:内置证书验证,可自定义证书;
  • 超时控制:支持连接、读取、写入超时配置,避免请求卡死。
相关推荐
w***76552 小时前
快速上手DCAT-Admin开发指南
android
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-知识点管理模块完整优化方案
java·前端·人工智能·spring boot
莫问前路漫漫2 小时前
Java Runtime Environment(JRE)全解析:Java 程序跨平台运行的核心基石
java·开发语言
进阶小白猿2 小时前
Java技术八股学习Day22
java·开发语言·学习
技术摆渡人2 小时前
专题二:【驱动进阶】打破 Linux 驱动开发的黑盒:从 GPIO 模拟到 DMA 陷阱全书
android·linux·驱动开发
蒟蒻的贤2 小时前
操作系统复习
java·开发语言·数据库
汤姆yu2 小时前
基于android的个人健康系统
android
sanggou2 小时前
Spring Boot 中基于 WebClient 的 SSE 流式接口实战
java·人工智能
未若君雅裁2 小时前
SpringBoot2.x与SpringBoot3.x自动配置注册的差异
java·spring boot