10、数据存储之SharedPreferences:轻量级键值对存储,读写用户配置与登录状态。
SharedPreferences,说白了就是 Android 系统自带的一个小本本。你往上面记个名字,记个开关状态,下次打开 App 还能找到。它专门用来存一些轻量级的配置数据,比如用户偏好、登录状态、设置开关这些。
我刚开始做 Android 开发那会儿,总觉得数据存储就得用数据库。后来发现,很多场景根本用不着那么重的东西。你想想看,用户选了个深色模式,你难道还要建张表去存?SharedPreferences 几行代码就搞定了。
10.1 SharedPreferences 是什么?
SharedPreferences 是一种键值对存储方式。它把数据以 XML 文件的形式保存在设备的内部存储中。每个键对应一个值,值可以是基本数据类型:String、int、boolean、float、long。
它的核心特点就三个:
- 轻量级:适合存少量配置数据,别往里塞大文本或图片
- 持久化:App 关闭后再打开,数据还在
- 线程安全:内部做了同步处理,但多进程场景要小心
适用场景:用户登录状态、主题设置、语言选择、新手引导是否展示过、上次阅读位置等。
10.2 基本用法:三步搞定
使用 SharedPreferences 其实就三步:获取实例、写入数据、读取数据。我习惯把这三步封装成一个工具类,这样项目中到处都能用。
10.2.1 获取 SharedPreferences 实例
// 方式一:通过 Context 获取
SharedPreferences sp = getSharedPreferences("my_config", Context.MODE_PRIVATE);
// 方式二:通过 Activity 获取(只能在该 Activity 中使用)
SharedPreferences sp = getPreferences(Context.MODE_PRIVATE);
// 方式三:通过 PreferenceManager 获取(默认文件名)
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
我个人推荐用第一种方式。文件名自己定义,方便管理。比如登录相关的数据存到 "login_prefs",设置相关的存到 "settings_prefs",各管各的,不乱。
注意:MODE_PRIVATE 是唯一安全的模式。MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 在 API 17 以后已经被废弃了,别再用。
10.2.2 写入数据
SharedPreferences sp = getSharedPreferences("my_config", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("username", "张三");
editor.putBoolean("is_login", true);
editor.putInt("theme_color", 1);
editor.apply(); // 或者 commit()
这里有个细节:apply() 和 commit() 有什么区别?
- apply():异步写入,没有返回值。速度快,推荐使用。
- commit():同步写入,返回 boolean 表示是否成功。如果你需要知道写入结果,用这个。
我一般都用 apply()。除非是极其关键的配置,比如支付状态,我才会用 commit() 确认一下。
10.2.3 读取数据
SharedPreferences sp = getSharedPreferences("my_config", Context.MODE_PRIVATE);
String username = sp.getString("username", "默认用户");
boolean isLogin = sp.getBoolean("is_login", false);
int themeColor = sp.getInt("theme_color", 0);
读取时一定要给默认值。为什么?因为如果键不存在,返回的就是你给的默认值。我曾经接手过一个项目,读取时没给默认值,结果用户第一次打开 App 直接崩溃了——因为返回了 null,后面又没判空。
10.3 实战:保存登录状态
登录状态是 SharedPreferences 最经典的应用场景。用户登录成功后,我们把 token 和登录标记存起来。下次打开 App,先检查这个标记,有就直接跳主页,没有就去登录页。
// 登录成功后保存
public void saveLoginInfo(String token, String username) {
SharedPreferences sp = getSharedPreferences("login_prefs", Context.MODE_PRIVATE);
sp.edit()
.putString("token", token)
.putString("username", username)
.putBoolean("is_login", true)
.apply();
}
// 检查是否登录
public boolean isLoggedIn() {
SharedPreferences sp = getSharedPreferences("login_prefs", Context.MODE_PRIVATE);
return sp.getBoolean("is_login", false);
}
// 退出登录时清除
public void logout() {
SharedPreferences sp = getSharedPreferences("login_prefs", Context.MODE_PRIVATE);
sp.edit().clear().apply();
}
小技巧:退出登录时用 clear() 清空整个文件,比一个个 remove() 省事多了。但要注意,如果这个文件里还存了其他不想清除的数据,那就别用 clear()。
10.4 避坑指南:我曾经踩过的坑
SharedPreferences 虽然简单,但坑也不少。我一个个说给你听。
10.4.1 不要存大量数据
SharedPreferences 底层是 XML 解析。数据一多,读取和写入都会变慢。我见过有人把几百条 JSON 字符串塞进去,结果每次读取都卡顿。这种场景,老老实实用数据库吧。
10.4.2 多进程问题
如果你用了多进程(android:process),SharedPreferences 默认是不支持跨进程同步的。两个进程同时读写,数据会乱掉。解决方案有两个:
- 用 ContentProvider 封装一层
- 用 MMKV(腾讯开源的替代方案)
我个人更推荐 MMKV,性能好,而且支持多进程。后面章节会详细讲。
10.4.3 不要存敏感信息
SharedPreferences 存的是明文。密码、支付密钥这些敏感信息,千万别往里放。如果非要存,记得加密。可以用 EncryptedSharedPreferences,它是 AndroidX Security 库提供的。
// 使用 EncryptedSharedPreferences
MasterKey masterKey = new MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.build();
SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
context,
"secure_prefs",
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
10.5 知识体系图
下面这张图帮你理清 SharedPreferences 的核心脉络:
10.6 总结
SharedPreferences 是 Android 开发中最基础的数据存储方式。它简单、轻量、够用。但你要记住它的边界:只适合存配置和状态,不适合存大量数据或敏感信息。
嗯,这里再补充一句:如果你觉得 SharedPreferences 不够用,或者遇到了性能瓶颈,可以考虑 MMKV 或者 DataStore。这些是更现代的替代方案,但基础原理是一样的。
一句话记住:SharedPreferences 就是你的 App 小本本,记点开关和状态,别往里面塞太多东西。