Android 本地存储深度对比:SharedPreferences、MMKV、Room 数据库怎么选?

Android 本地存储深度对比:SharedPreferences、MMKV、Room 数据库怎么选?

本地存储是 App 的基石,但很多项目里它却是最容易被"随手乱用"的地方。

本文从 原理 → 性能 → 一致性 → 适用场景 ​ 四个维度,系统对比 SharedPreferences、MMKV、Room,帮你彻底告别选型焦虑。


一、先给结论:一句话选型指南

场景 首选方案
简单配置(开关、主题、引导页) ✅ SharedPreferences
高频写入 / 跨进程 / 性能敏感 ✅ MMKV
结构化数据 / 复杂查询 / 事务 ✅ Room
大文本、JSON、对象集合 ❌ SP / MMKV → ✅ Room
需要数据迁移、版本管理 ❌ SP / MMKV → ✅ Room

二、SharedPreferences:老牌配置存储

1. 工作原理

  • XML 文件存储

  • 全量加载到内存

  • 通过 Editor.commit() / apply() 写入

    val sp = getSharedPreferences("config", MODE_PRIVATE)
    sp.edit().putBoolean("dark_mode", true).apply()


2. 优点

✅ API 简单

✅ 官方原生支持

✅ 学习成本低

✅ 无需额外依赖


3. 致命缺点

全量读写(哪怕只改一个字段)

apply() 可能 ANR(Activity 暂停时会等待)

跨进程不安全

不支持复杂数据类型

容易引发 GC 压力

apply() 本质是把写磁盘任务丢到 Queue,系统会在 Activity 生命周期切换时强制执行。


4. 典型误用

复制代码
// ❌ 把用户列表存进 SP
sp.edit().putString("user_list", json).apply()

5. 适用场景

  • 开关状态

  • 主题模式

  • 首次启动标识

  • 低频、小数据


三、MMKV:腾讯开源的高性能 KV 存储

1. 核心原理

  • mmap 内存映射

  • Protobuf 二进制协议

  • 增量更新

  • 跨进程锁

    MMKV.initialize(this)
    val kv = MMKV.defaultMMKV()
    kv.encode("token", token)


2. 性能优势(对比 SP)

指标 SP MMKV
写入速度 极快
读取速度
跨进程 不支持 ✅ 支持
ANR 风险
文件大小

3. 为什么 MMKV 快?

✅ mmap 避免内核态拷贝

✅ Protobuf 紧凑编码

✅ 只写变化数据

✅ 无 GC 压力


4. 优点

✅ 性能碾压 SP

✅ 支持跨进程

✅ 支持加密

✅ API 友好

✅ 微信级验证


5. 缺点

❌ 不适合复杂查询

❌ 不适合关系型数据

❌ 调试不如数据库直观


6. 适用场景

  • Token / Cookie

  • 用户偏好

  • 高频计数器

  • 跨进程数据共享


四、Room:结构化数据的终极方案

1. 架构定位

Room 是 SQLite 的 ORM 封装 ,属于 Jetpack 官方组件

复制代码
@Entity
data class User(
    @PrimaryKey val uid: Int,
    val name: String
)

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE uid = :id")
    suspend fun getUser(id: Int): User
}

2. 核心优势

✅ 编译期 SQL 校验

✅ 强类型

✅ 支持 LiveData / Flow

✅ 支持事务

✅ 内置 Migration


3. 性能特点

操作 表现
单条读写 中等
批量写入 ✅ 优秀
复杂查询 ✅ 极强
随机 KV 访问 一般

4. 什么时候必须用 Room?

✅ 用户表 / 订单表

✅ 缓存列表数据

✅ 需要排序 / 分页 / 过滤

✅ 需要数据版本升级


5. 缺点

❌ 上手成本高

❌ 简单配置显得"杀鸡用牛刀"

❌ 启动成本略高


五、三大方案横向对比(重点)

维度 SharedPreferences MMKV Room
数据结构 KV KV 关系型
性能 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐
跨进程
事务
查询能力
学习成本 ⭐⭐ ⭐⭐⭐⭐
官方维护 ⚠️(腾讯)

六、真实项目中的最佳实践

✅ 混合使用策略(推荐)

复制代码
SP     → UI 配置、开关
MMKV   → Token、用户信息快照
Room   → 业务数据、缓存列表

✅ 不推荐的做法

❌ 把 List / Map 序列化成 String 存 SP

❌ 用 MMKV 当数据库

❌ Room 存 boolean 开关


✅ 性能敏感场景示例

登录态管理

复制代码
MMKV.defaultMMKV().encode("user_id", id)

首页 Feed 缓存

复制代码
@Dao
@Query("SELECT * FROM feed ORDER BY time DESC LIMIT 20")
fun getFeed(): Flow<List<Feed>>

七、迁移建议

SP → MMKV

复制代码
MMKV.migrate(userSp)

SP → Room

  • 启动时读取 SP

  • 写入 Room

  • 删除旧 SP


八、总结

没有最好的存储方案,只有最合适的存储方案。

  • SharedPreferences:简单配置的最后一道防线

  • MMKV:性能与效率的首选 KV

  • Room:结构化数据的唯一正解

记住一句话:

能用 SP 的别用 Room,该用 Room 的别硬塞 SP。

相关推荐
资讯第一线1 小时前
SQL Server工具:WinToolsPlus 之 SQL Server 日志清理/Suspect/质疑/置疑/可疑/单用户等 修复
数据库·oracle
追风少年ii1 小时前
课前准备--蛋白质PDB文件与PDBQT文件的格式与区别
数据库·数据分析·分子动力学·分子对接
hopsky2 小时前
《HBase 权威指南》 Lars George
大数据·数据库·hbase
Architect_Lee2 小时前
mac快速安装mysql
数据库·mysql·macos
Elastic 中国社区官方博客2 小时前
Elasticsearch:列式索引模式 - Columnar index mode
大数据·数据库·elasticsearch·搜索引擎·全文检索
阿巴斯甜2 小时前
adb push .../AdapterService.apk 和 .../区别:
android
Lysander.Jovian2 小时前
Nginx服务2
运维·数据库·nginx
小张同学a.2 小时前
zabbix企业级监控平台4——分布式监控与grafana数据可视化
linux·运维·数据库·分布式·信息可视化·zabbix·grafana
渣渣盟2 小时前
当 Redis 写入不再是瓶颈后,Flink 任务的反压可能来自哪里?如何系统性地定位和解决 Flink 反压问题?
数据库·redis·flink