跳到主要内容

SharedPreferences

问题

SharedPreferences 的原理是什么?有哪些已知问题?

答案

基本原理

SharedPreferences 将数据以 XML 文件形式存储在 /data/data/<package>/shared_prefs/ 目录下:

已知问题

1. 全量写入

每次调用 apply() / commit() 都会将整个 Map 序列化为 XML 写入磁盘,数据量大时性能差。

2. apply 导致 ANR

apply() 虽然异步写磁盘,但 Activity onStop 时会在主线程等待所有 apply 任务完成:

// ❌ 高频调用 apply 可能导致 ANR
fun trackEvent(key: String, value: Int) {
prefs.edit().putInt(key, value).apply()
// onStop 时主线程会等待这些 apply 完成
}

3. 非类型安全

// ❌ key 写错或类型不匹配,编译期无法发现
val name = prefs.getString("user_name", "") // 运行时才发现问题
val age = prefs.getInt("user_age", 0)

4. 不支持跨进程

MODE_MULTI_PROCESS 已废弃,多进程读写 SP 不可靠。

commit vs apply

特性commit()apply()
执行方式同步写磁盘异步写磁盘
返回值boolean(是否成功)void
阻塞主线程✅ 写入时阻塞❌ 但 onStop 时会等待
推荐场景需要确认写入成功一般场景
为什么不推荐 SP

SP 的全量写入、ANR 风险和类型不安全问题使其不适合现代开发。Google 推荐使用 DataStore 替代。


常见面试问题

Q1: SP 的 apply 一定不会 ANR 吗?

答案

不是。apply() 将写入任务提交到 QueuedWork,在 Activity.onStop()Service.onStartCommand() 等生命周期节点,主线程会调用 QueuedWork.waitToFinish() 等待所有 pending 的 apply 完成。如果有大量或大数据量的 apply 任务积压,就会在主线程阻塞导致 ANR。

Q2: SP 第一次读取为什么可能卡顿?

答案

首次调用 getSharedPreferences() 时,会在子线程加载 XML 文件到内存。但如果在文件加载完成前就调用 getString() 等读取方法,主线程会被 await() 阻塞,等待文件加载完成。文件越大,阻塞时间越长。

相关链接