第2章 OkHttp内置Cache类初始化与配置
OkHttp的缓存能力由 Cache 类直接提供。理解其构造参数与磁盘布局是正确配置的基础。本章围绕 Cache(directory, maxSize) 构造函数,详细拆解每个参数的含义、默认行为以及缓存文件在磁盘上的组织结构,并给出可复用的初始化模板。
2.1 Cache 构造函数的两个核心参数
Cache 仅有一个公开构造函数,签名如下:
public Cache(File directory, long maxSize)
两个参数的含义与约束:
| 参数 | 类型 | 说明 | 常见值 |
|---|---|---|---|
| directory | File |
缓存文件存储的目录路径。如果目录不存在,OkHttp 会自动创建(包含必要时创建父目录)。必须是一个可写目录,否则初始化阶段会抛出 IOException。 |
context.cacheDir / new File("/data/okhttp_cache") |
| maxSize | long |
缓存最大字节数。OkHttp 通过 DiskLruCache 进行清理,当总大小超过此值时会淘汰最旧的条目。最小值建议为 1(非零),实际项目中常用 10 * 1024 * 1024(10MB)以上。 |
50 * 1024 * 1024L |
⚠ 注意:
maxSize 并非严格上限,OkHttp 会在后台异步清理,实际占用可能短暂超过设定值。建议预留 10%~20% 的缓冲区。
2.2 默认缓存目录与平台差异
OkHttp 没有硬编码的“默认”缓存目录 —— 你必须显式提供一个 File 对象。但在 Android 和 Java 服务端场景下,存在常见约定路径:
- Android:使用
context.getCacheDir()或context.getExternalCacheDir()。内部存储路径一般为/data/data/<package>/cache/okhttp_cache。 - Java 服务端:使用
new File("/var/cache/okhttp")或Paths.get(System.getProperty("java.io.tmpdir"), "okhttp-cache").toFile()。
// Android 示例
File cacheDir = new File(context.getCacheDir(), "http-cache");
long cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(cacheDir, cacheSize);
2.3 缓存文件结构深度解析
初始化完成后,directory 下会生成以下文件/子目录:
- journal(核心日志文件):记录所有缓存条目的状态(DIRTY、CLEAN、READ、REMOVE)。是缓存一致性的保障。
- 条目文件(.0 / .1):每个缓存条目由两个文件组成:
<key>.0(元数据,如响应头)和<key>.1(响应体数据)。键是 URL 的 MD5 哈希。 - 临时文件(.tmp):写入过程中产生的临时文件,写入完成会被重命名为正式条目文件。
典型磁盘布局(tree 形式):
/cache/okhttp/
├── journal
├── 2a1b3c4d5e6f7890.0
├── 2a1b3c4d5e6f7890.1
├── ffeeddccbbaa9988.0
├── ffeeddccbbaa9988.1
└── ...
💡 调试技巧:检查 journal 文件的前几行可以确认缓存是否正常工作。首行固定为
libcore.io.DiskLruCache,第二行是版本号和应用版本号。
2.4 Cache 初始化流程与文件关系图
2.5 缓存大小限制的工程实践
maxSize 的选取直接关系到缓存命中率和磁盘占用。以下为不同场景的推荐值:
| 应用类型 | 推荐 maxSize | 理由 |
|---|---|---|
| 轻量App(少量图片API) | 5 ~ 10 MB | 避免频繁GC与I/O |
| 媒体密集App(图片/视频) | 50 ~ 200 MB | 覆盖多数重复请求 |
| 服务端反向代理 | 500 MB ~ 数 GB | 根据业务QPS与时效性 |
2.6 常见错误与调试
- java.io.IOException: No space left on device —— maxSize 设置过大,或磁盘已满。检查剩余空间并调整上限。
- java.io.FileNotFoundException: ... (Read-only file system) —— 传入的 directory 权限不足。确保路径可写,尤其是 Android 外部存储需要额外权限。
- 缓存大小无变化 —— 未正确配置
Cache-Control响应头,OkHttp 不缓存无缓存指令的响应。参见第4章。
🔧 调试常用代码:打印缓存统计信息
Cache cache = okHttpClient.cache();
if (cache != null) {
System.out.println("缓存命中: " + cache.hitCount());
System.out.println("缓存请求: " + cache.requestCount());
System.out.println("网络请求: " + cache.networkCount());
}
2.7 性能与稳定性优化要点
- 目录隔离:不同业务线使用独立的 Cache 实例,避免单个大缓存污染。
- 写入缓冲:OkHttp 内部使用
BufferedSink避免频繁小文件 I/O,无需额外配置。 - journal 重建:若 journal 文件受损,DiskLruCache 会触发重建,此时读写性能下降。确保进程不强行 kill 写操作。
- 文件描述符限制:缓存条目过多时打开大量文件句柄。Linux 可通过
ulimit -n调整,或适当降低 maxSize 减少条目数。