1. 本地存储方案全景:方案分类、演进历史、适用场景概览
1.1 方案分类
Android 本地存储方案按数据结构、访问模式与持久粒度可划分为四大类:
| 类别 | 典型方案 | 底层机制 | 数据形态 |
|---|---|---|---|
| 键值存储 | SharedPreferences、DataStore、MMKV | XML / ProtoBuf / mmap | 简单键值对 |
| 关系型数据库 | SQLite、Room | B-Tree / WAL / SQL | 结构化表数据 |
| 对象存储 | ObjectBox、Realm | NoSQL / ACID | 以对象为中心的持久化 |
| 文件存储 | Internal / External / Cache | 文件系统 | 任意二进制、JSON、文件 |
1.2 演进历史
Android 存储方案经历了三个主要阶段:
- 早期(API 1 ~ 26):SharedPreferences + SQLite 互为主流,前者用于配置,后者用于结构化数据。开发者直接操作 Cursor 和 ContentValues,并发与类型安全问题突出。
- 中期(API 26 ~ 30):Google 推出
Jetpack Room,封装 SQLite 并提供编译时 SQL 校验;同时MMKV在微信场景下广泛使用,以 mmap 替代 I/O 提升性能。 - 近期(API 30+):
DataStore替代 SharedPreferences,基于 ProtoBuf 或 Preferences 提供协程 / Flow 支持;ObjectBox等 NoSQL 方案在复杂对象场景中开始采用。
关键转折:从“手工管理 SQLite”到“注解驱动的 Room”,再从“同步 SP”到“异步 DataStore”,体现了 Jetpack 对存储层架构的统一化与响应式改造。
1.3 适用场景概览
不同方案面向的能力象限差异明显,选型需重点匹配以下特征:
| 场景 | 推荐方案 | 避坑点 |
|---|---|---|
| 应用配置、用户偏好(小型键值) | DataStore(Preferences) | 体积超过 100KB 需改用 Proto DataStore |
| 复杂查询、多表关联、迁移 | Room | Room 依赖编译期注解处理器,增量编译需配置 KSP |
| 超高频读写(界面帧内多次) | MMKV | 跨进程通信需额外实现 ContentProvider |
| 大量二进制文件(图片、日志) | File / Cache | 系统清理 Cache 时不通知;文件路径暴露可能导致安全漏洞 |
实战建议:大多数中大型 App 的最佳实践是 DataStore + Room 组合——DataStore 管理轻量配置,Room 管理业务实体,避免单一方案承载所有场景。
1.4 方案分类与演进图
架构风险点:
- SharedPreferences 的
apply()异步行为在系统进程被杀时可能丢失最近写入;且跨进程并发无任何保护。 - Room 的编译期 SQL 校验依赖 AGP 与 KSP 版本匹配,升级 Gradle 时易导致构建失败。
- MMKV 虽然快,但无法支持多条件查询与索引;若业务模型从键值转向实体,迁移成本高于 Room。
1.5 落地步骤与验收标准
无论选择何种方案,首章即应确立以下标准化落地流程:
- 明确数据生命周期:区分持久配置、缓存、业务实体,按生命周期分方案。
- 定义存储层接口:用 Repository 或 DataSource 接口隔离具体实现,方便后期替换。
- 合规与安全:敏感数据必须加密(如 EncryptedSharedPreferences / SQLCipher);文件存储禁用 World-readable 权限。
- 单元测试覆盖:为每个存储层编写隔离测试(Room 可用 in-memory database)。
- 基准测试:在旗舰机与低端机上分别测量读写延迟(建议 < 5ms / 次)。
验收标准示例:DataStore 写入 100 条键值对耗时 ≤ 200ms;Room 单表 10 万行查询含索引过滤 ≤ 50ms;MMKV 在不同 Size 下 mmap 回写出错率 0%。