Retrofit与OkHttp缓存基础
本章聚焦 OkHttp 缓存模块的核心组件与运行机制,彻底理解 Cache、CacheStrategy 以及缓存目录/大小配置,才能在后续章节实现精确的动态缓存策略。
OkHttp 缓存架构概述
OkHttp 的缓存层位于应用层与网络层之间,由 CacheInterceptor 统一处理。一次请求进入后的执行顺序:
- 应用发起请求 →
OkHttpClient - 经过拦截器链,到达 CacheInterceptor
- CacheInterceptor 利用 CacheStrategy 判断是否使用缓存
- 若缓存命中且有效,直接返回缓存响应;否则请求网络
- 网络响应返回后更新缓存
关键认知: Retrofit 本身不管理缓存,所有缓存行为全部委托给底层 OkHttp 的 Cache 组件。因此掌握 OkHttp 缓存是动态缓存策略的根基。
Cache 类与 CacheStrategy
| 组件 | 职责 | 关键方法/属性 |
|---|---|---|
Cache | 管理磁盘存储,提供缓存的增删改查 | put()、get()、remove()、maxSize()、writeSuccessCount |
CacheStrategy | 根据缓存头与请求头决策是否使用缓存 | get() 静态方法,返回 CacheStrategy 对象 |
CacheStrategy.Factory | 解析请求与缓存响应,生成策略对象 | 内部维护 request、response、sentRequestMillis、receivedResponseMillis |
CacheStrategy 决策规则: 根据 HTTP 缓存头(如
Cache-Control、Expires、ETag)计算缓存的有效性,并返回是否使用网络、是否使用缓存、或返回 504 网关超时。
缓存目录与大小配置
创建 Cache 对象需要指定磁盘目录和最大字节数。目录必须可写,否则 OkHttp 会静默降级(不缓存)。
// Java 示例
File cacheDir = new File(context.getCacheDir(), "http_cache");
int cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(cacheDir, cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
// Kotlin 示例
val cacheDir = File(context.cacheDir, "http_cache")
val cacheSize = 10L * 1024 * 1024
val cache = Cache(cacheDir, cacheSize)
val client = OkHttpClient.Builder()
.cache(cache)
.build()
常见错误: 目录路径使用
getExternalCacheDir() 时,若外部存储不可用,Cache 构造不会报错但缓存失效。建议统一使用 getCacheDir()。另外 maxSize 单位是字节,建议用 int 或 long 显式声明。
缓存策略决策流程(SVG)
缓存配置参数对比
| 参数 | 类型 | 作用 | 默认值 |
|---|---|---|---|
maxSize | long | 缓存磁盘最大字节数 | 无默认,必须指定 |
directory | File | 缓存文件存放目录 | 无默认,必须指定 |
Cache-Control: max-age | 秒 | 缓存相对有效期 | 由服务器决定 |
Cache-Control: max-stale | 秒 | 允许使用过期缓存的最大宽限时间 | 0 |
Cache-Control: min-fresh | 秒 | 要求缓存剩余有效期至少多少秒 | 0 |
noCache | boolean | 禁止使用缓存,但允许存储缓存 | false |
noStore | boolean | 禁止存储和读取缓存 | false |
调试技巧: 开启 OkHttp 日志拦截器可观察缓存命中情况,日志输出
Cache: HIT / MISS / CONDITIONAL_HIT。配合 cache.evictAll() 可清空缓存用于测试。