文章目录
1. 前言
作为 Android 入门时学习的第一个简单的存储方案,SharedPreference 是每个初学者绕不开的知识点。它使用简单,常常用来存储键值对数据,比如一些配置信息。但是如果你把它作为主要存储方案,存储大量数据时,请慎用。因为它有着令人 震惊的性能缺陷。
2. SharedPreference 的使用回顾
2.1 写数据
先获取 SharedPreferences 对象。
// 文件名:my_config
// 模式:MODE_PRIVATE 只有本应用能访问
SharedPreferences sp = getSharedPreferences("my_config", Context.MODE_PRIVATE);
- 方式一:异步写数据 apply
apply 后不写入磁盘,而是择机由系统调度,使用子线程写入。
SharedPreferences.Editor editor = sp.edit();
editor.putString("username", "zhangsan");
editor.putInt("age", 20);
editor.putBoolean("is_login", true);
editor.putFloat("score", 95.5f);
editor.putLong("last_time", System.currentTimeMillis());
// 异步提交
editor.apply();
- 方式二:同步写数据 commit
同步写的优点是有返回值,缺点是阻塞当前线程。
boolean success = editor.commit();
if (success) {
// 写入磁盘成功
}
2.2 读数据
读取数据很简单,根据key获取value,可以根据需要读取不同类型的值。
String username = sp.getString("username", "默认名字");
int age = sp.getInt("age", 0);
boolean isLogin = sp.getBoolean("is_login", false);
float score = sp.getFloat("score", 0f);
long lastTime = sp.getLong("last_time", 0L);
3. SharedPreference 的缺陷
3.1 全量读写XML文件
SharedPreference 存储数据的原理是将数据写入 XML 文件。
读写文件本来就是比较耗费性能的事,你敢想象吗?每次新增或修改一个键值对时,它竟然要全量读写底层的XML文件! 也就是说,即使你只修改其中一个值,它也会把整个XML文件读到内存,然后修改,再全部写回XML文件!
假如你的XML文件里有一万条数据,天呐!工作量是多么大,难怪APP会卡了吧。
3.2 页面暂停强制阻塞写文件
有些朋友可能注意到 SharedPreference 为了提高性能,在更新数据时不阻塞UI,设计了 apply 的提交方式。它不会立刻写入文件,而是择机异步写入,从而避免大量 IO 操作阻塞主线程。
但是它还有一个逆天的设计:在页面生命周期 Pause 时,强制阻塞 UI 线程,进行 SharedPreference 的文件写入。
这是为了防止数据丢失的策略,但就是这个策略会导致在页面跳转时,如果你有大量的 SharedPreference 等待写入,就会跳转卡顿!
3.3 多线程不安全
还有一个无法解决的问题,SharedPreference 的文件读写是没有锁保护的。
也就意味着多线程或者多进程下,都可以读写文件,你拿到的数据可能不是最新的,也就是所谓的脏数据。你使用apply 写入的时候,如果别人也用了 apply 写入,那么可能你的数据被别人覆盖。在大型项目中太危险了啊!
4. 总结
SharedPreference 是Android开发初学者必须了解的一个简单的存储工具,但随着学习的深入,我们要知道它的原理和优缺点。在复杂项目中,它的缺点已经不容忽视。主要包括:
- 全量读写XML文件
- 生命周期阻塞写入
- 多线程不安全
那么问题来了,我们不用它,该用什么呢?我们下篇文章接着讲:替代 SharedPreference 的最佳键值对存储方案:MMKV
1306

被折叠的 条评论
为什么被折叠?



