3. 配置磁盘缓存目录与大小

3.1 原理概述

OkHttp 的磁盘缓存基于 LRU(Least Recently Used) 淘汰策略,将 HTTP 响应体持久化到文件系统。缓存结构由一个目录路径和一个最大字节数共同定义:

  • 目录路径:存储缓存文件的文件夹,需保证应用进程拥有读写权限。
  • 最大字节限制:缓存文件总大小的上限。当超出时,OkHttp 自动删除最久未使用的条目。

配置正确后,OkHttp 在发送请求时会先查询该目录下是否存在有效缓存;若存在则直接返回,否则发起网络请求并将响应写入缓存。

核心 API:
Cache(File directory, long maxSize)
创建后需通过 OkHttpClient.Builder().cache(cache) 装配到客户端。

3.2 实现流程

  1. 确定缓存目录(优先使用内部缓存目录,避免权限与外部存储不可用问题)。
  2. 实例化 Cache 对象,传入目录文件句柄与最大字节数。
  3. 构建 OkHttpClient 并关联此 Cache 实例。
  4. 验证配置:通过 cache().directory() 和 cache().maxSize() 读取实际值。

3.3 代码示例(Kotlin)

val cacheDir = File(context.cacheDir, "okhttp_cache")
// 确保目录存在
cacheDir.mkdirs()

// 设置最大缓存大小为 50 MB
val cacheSize = 50L * 1024 * 1024 // 50 * 1024 * 1024 = 52,428,800 字节

val cache = Cache(cacheDir, cacheSize)

val client = OkHttpClient.Builder()
    .cache(cache)
    .build()

3.4 目录路径选择对比

路径类型 可用性 权限 推荐场景
context.cacheDir 始终可用 应用私有,无需额外声明 首选,适用于绝大多数应用
context.externalCacheDir 外部存储挂载时可用 需声明 WRITE_EXTERNAL_STORAGE 需要更大空间的图片/视频缓存
自定义公有目录 取决于存储状态 权限复杂,且可能被用户清理 不推荐

⚠ 常见错误:权限不足
使用外部缓存目录但忘记声明 WRITE_EXTERNAL_STORAGE 权限会导致 IOException;Android 10+ 建议使用 context.cacheDir 避免分区存储限制。

3.5 最大字节限制策略

建议根据应用数据类型设定合理上限:

  • 纯文本接口(REST API):5MB~10MB 已足够。
  • 富媒体接口(图片/视频):50MB~100MB。
  • 通用原则:不超过可用磁盘空间的 5%,且做好运行时动态调整的准备。

配置过小会导致缓存命中率低、频繁淘汰;配置过大则会占用用户存储空间,可能被系统或用户清理。

3.6 调试与验证

// 打印当前缓存配置
logger.debug("Cache directory: ${client.cache?.directory?.absolutePath}")
logger.debug("Cache max size: ${client.cache?.maxSize}")
// 打印缓存统计信息(需先执行一次请求)
client.cache?.let {
    logger.debug("Hit count: ${it.hitCount}")
    logger.debug("Miss count: ${it.missCount}")
    logger.debug("Network count: ${it.networkCount}")
    logger.debug("Request count: ${it.requestCount}")
}

观察日志:missCount 只有在请求完成后才会更新;首次请求后应当看到 hitCount 逐步增长。

3.7 性能与稳定性优化

  • 在后台线程创建目录,避免在主线程执行文件 I/O。
  • 使用 File.mkdirs() 后检查返回值;若失败则设置 noCache()。
  • 定期(比如应用启动时)清理无效的 .0 和 .1 文件(被中断写入的残留)。
  • 避免高频并发写入:OkHttp 内部已做同步,但极端场景可考虑 Dispatcher.maxRequests 控制连接数。

3.8 配置流程图

OkHttp 磁盘缓存配置流程 1. 选择缓存目录 2. mkdirs() 确保存在 3. 限定最大字节数 4. Cache(directory, maxSize) 5. OkHttpClient.cache(cache) 💡 推荐 目录:context.cacheDir 大小:10MB~50MB 权限:无需额外声明

🔍 调试技巧
想要快速验证缓存是否生效?可以先用 client.cache?.maxSize = 0 禁用缓存,再设置期望值,对比 hitCount 在两次相同请求后的差异。

3.9 常见错误与避坑

错误现象 根因 解决方案
缓存目录为 null 导致 NPE 未检查 cacheDir 是否为 null 始终判断 cacheDir?.let { … }
缓存从未命中 设置了 noCache() 或 CacheControl.FORCE_NETWORK 检查请求/响应头是否禁止缓存(如 Cache-Control: no-store)
磁盘空间迅速占满 maxSize 设置过大,或响应体未被正确复用 调小上限,并开启压缩(如 gzip)

通过上述配置与检查,你可以高效利用 OkHttp 的磁盘缓存减少网络请求,提升用户体验。