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 的核心脉络:

SharedPreferences 轻量级键值对 持久化存储 线程安全 基本用法三步走 1. 获取实例 2. 写入数据 3. 读取数据 避坑指南 不要存大量数据 多进程不同步 不要存敏感信息

10.6 总结

SharedPreferences 是 Android 开发中最基础的数据存储方式。它简单、轻量、够用。但你要记住它的边界:只适合存配置和状态,不适合存大量数据或敏感信息。

嗯,这里再补充一句:如果你觉得 SharedPreferences 不够用,或者遇到了性能瓶颈,可以考虑 MMKV 或者 DataStore。这些是更现代的替代方案,但基础原理是一样的。

一句话记住:SharedPreferences 就是你的 App 小本本,记点开关和状态,别往里面塞太多东西。

公众号:蓝海资料掘金营,微信deep3321