3. 配置磁盘缓存目录与大小
3.1 原理概述
OkHttp 的磁盘缓存基于 LRU(Least Recently Used) 淘汰策略,将 HTTP 响应体持久化到文件系统。缓存结构由一个目录路径和一个最大字节数共同定义:
- 目录路径:存储缓存文件的文件夹,需保证应用进程拥有读写权限。
- 最大字节限制:缓存文件总大小的上限。当超出时,OkHttp 自动删除最久未使用的条目。
配置正确后,OkHttp 在发送请求时会先查询该目录下是否存在有效缓存;若存在则直接返回,否则发起网络请求并将响应写入缓存。
核心 API:Cache(File directory, long maxSize)
创建后需通过 OkHttpClient.Builder().cache(cache) 装配到客户端。
3.2 实现流程
- 确定缓存目录(优先使用内部缓存目录,避免权限与外部存储不可用问题)。
- 实例化 Cache 对象,传入目录文件句柄与最大字节数。
- 构建 OkHttpClient 并关联此 Cache 实例。
- 验证配置:通过
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 配置流程图
🔍 调试技巧
想要快速验证缓存是否生效?可以先用 client.cache?.maxSize = 0 禁用缓存,再设置期望值,对比 hitCount 在两次相同请求后的差异。
3.9 常见错误与避坑
| 错误现象 | 根因 | 解决方案 |
|---|---|---|
| 缓存目录为 null 导致 NPE | 未检查 cacheDir 是否为 null |
始终判断 cacheDir?.let { … } |
| 缓存从未命中 | 设置了 noCache() 或 CacheControl.FORCE_NETWORK |
检查请求/响应头是否禁止缓存(如 Cache-Control: no-store) |
| 磁盘空间迅速占满 | maxSize 设置过大,或响应体未被正确复用 |
调小上限,并开启压缩(如 gzip) |
通过上述配置与检查,你可以高效利用 OkHttp 的磁盘缓存减少网络请求,提升用户体验。