第1章 离线缓存核心概念
离线缓存是移动应用中提升用户体验、保障服务可用性的关键技术手段。在 Retrofit 框架中,离线缓存的实现依赖于对缓存必要性、离线场景、网络协同及失效机制四个核心维度的深入理解。本章将从原理层面拆解这些概念,为后续实现章节打下理论基础。
1.1 为什么需要离线缓存
离线缓存的核心价值在于消除网络不确定性。以下是需要离线缓存的几个关键理由:
- 提升响应速度:缓存数据直接从本地读取,避免网络延迟,典型场景下可将页面加载时间从秒级降至毫秒级。
- 降低流量消耗:重复请求命中缓存后不再消耗移动数据,对高频访问接口可减少 60%–80% 的流量开支。
- 保障弱网可用:在网络波动或断开时,缓存提供降级数据,保证 App 核心功能不中断。
- 减轻服务器压力:通过缓存拦截重复请求,后端负载可降低 30%–50%,尤其适用于高并发移动应用。
实践观点:缓存不是“存储副本”,而是可用性与实时性之间的权衡策略。在 Retrofit 中,缓存策略通过 OkHttp 拦截器层控制,开发者需要根据业务场景选择合适的模式。
1.2 离线场景分析
离线场景并非单一的“没有网络”,而是包含多种细分状态,不同状态对缓存行为的要求差异显著:
| 场景类型 | 网络状态 | 缓存可用性要求 | 典型处理策略 |
|---|---|---|---|
| 完全离线 | 无任何网络连接 | 必须返回缓存 | 读取本地缓存,无缓存则显示错误占位 |
| 弱网环境 | 信号强度低 / 高延迟 | 优先返回缓存,后台静默刷新 | 缓存优先 + 过期后异步更新 |
| 间歇性连接 | 网络频繁切换 / 短暂断开 | 缓存需具备断点续传能力 | 本地持久化 + 请求队列重试 |
| 省流量模式 | 用户主动限制网络使用 | 仅使用缓存,禁止自动请求 | 缓存命中失败时提示用户手动刷新 |
注意:离线场景下返回的缓存数据可能已过期。必须在前端 UI 层明确展示“离线模式”或“缓存数据”标识,避免用户基于过时信息做出错误决策。
1.3 缓存与网络协同工作模式
缓存与网络并非二选一,而是通过协同策略实现实时性与可用性的平衡。Retrofit 通过 OkHttp 的 CacheInterceptor 和自定义拦截器支持以下四种协同模式:
- 缓存优先(Cache First):有缓存直接返回,无缓存或缓存过期才发起网络请求。适用于新闻列表、商品分类等非实时数据。
- 网络优先(Network First):先请求网络,失败或超时后降级到缓存。适用于订单状态、支付结果等强实时场景。
- 缓存优先 + 后台刷新(Stale-While-Revalidate):立即返回缓存,同时异步发起网络请求更新缓存。适用于信息流、推荐列表。
- 网络优先 + 缓存降级(Network With Cache Fallback):先尝试网络,若网络不可用则直接返回缓存。适用于用户详情、配置拉取。
以下是一个 Retrofit 中集成 OkHttp 缓存的基本配置示例,展示如何设置缓存目录、大小及默认缓存控制头:
// 1. 创建缓存目录与容量
File cacheDir = new File(context.getCacheDir(), "retrofit_cache");
long cacheSize = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(cacheDir, cacheSize);
// 2. 构建 OkHttpClient 并附加缓存
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(new CacheInterceptor()) // 自定义缓存策略
.build();
// 3. 创建 Retrofit 实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
协同选择建议:对于同一 App 内的不同接口,可以在自定义
CacheInterceptor 中根据请求 URL 或头部标记动态切换策略,而不是全局绑定一种模式。
1.4 缓存失效机制
缓存如果不失效,数据将永远陈旧。失效机制是保证缓存数据渐进一致的关键手段。常见的失效方式包括:
- TTL(Time-To-Live)过期:缓存写入后设置有效时间,到期后自动标记为过期。适用于时效性明确的数据(如 5 分钟内的天气信息)。
- LRU(Least Recently Used)淘汰:当缓存容量达到上限时,淘汰最久未使用的条目。适用于缓存空间固定、访问模式不均匀的场景。
- 手动清空:用户主动触发“清除缓存”或 App 版本升级时整体清空。适用于配置变更、登出等状态重置场景。
- 版本变更失效:后端 API 版本号变化时,客户端自动废弃旧缓存。适用于接口协议升级或数据结构调整。
关键指标:
缓存命中率 = 缓存返回次数 / 总请求次数 × 100%
过期数据占比 = 过期仍被返回次数 / 缓存返回总次数 × 100%
这两项指标需持续监控,命中率低于 40% 说明策略过于保守,过期占比高于 15% 说明 TTL 设置过长。
缓存命中率 = 缓存返回次数 / 总请求次数 × 100%
过期数据占比 = 过期仍被返回次数 / 缓存返回总次数 × 100%
这两项指标需持续监控,命中率低于 40% 说明策略过于保守,过期占比高于 15% 说明 TTL 设置过长。
1.5 核心概念对比与总结
下表对本章四个核心概念进行横向对比,帮助你在实际项目中快速定位缓存策略的侧重点:
| 核心概念 | 关键描述 | 主要作用 | 典型实现方式 |
|---|---|---|---|
| 缓存必要性 | 网络不稳定时保证可用性 | 提升用户体验、节省流量 | 本地持久化、内存缓存、磁盘缓存 |
| 离线场景 | 无网或弱网环境下的数据供给 | 保障核心功能不中断 | 场景识别、降级策略、提示引导 |
| 缓存与网络协同 | 缓存与请求相互配合 | 平衡实时性与效率 | 四种协同模式、自定义拦截器 |
| 缓存失效机制 | 控制缓存的生命周期 | 保证数据新鲜度、防止内存泄漏 | TTL、LRU、版本控制、手动清空 |
常见误区:不要把“缓存失效”等同于“缓存删除”。失效仅标记数据不可用,实际删除由 LRU 或手动策略触发。过早物理删除会导致缓存抖动,降低命中率。
掌握这四个核心概念是搭建 Retrofit 离线缓存体系的基石。接下来的章节将从缓存拦截器实现、OkHttp 缓存配置、离线策略编排等方向逐步深入,将本章的理论转化为可运行的代码。