Flutter 数据存储之 SharedPreferences 键值对存储
本文介绍了Flutter中SharedPreferences(SP)的使用方法和工程化封装方案。SP是官方提供的轻量级本地存储方案,支持基本数据类型和字符串列表,底层基于Android/iOS原生实现。文章详细说明了SP的核心概念、使用步骤(添加依赖、获取实例、数据操作),并重点分享了工程化封装思路:通过SPKeys类统一管理键值,利用SPUtils工具类实现同步化调用,在应用启动时预加载实例。这
目录
一、简介
SharedPreferences 是 Flutter 官方提供的轻量级本地数据存储方案,适用于保存用户配置、登录状态、简单设置等键值对(Key-Value)数据。
其底层基于平台原生实现(Android 的 SharedPreferences 和 iOS 的 NSUserDefaults),具有操作简单、读写高效的特点。
二、核心概念
|
特性 |
说明 |
|
数据类型支持 |
|
|
存储位置 |
自动持久化到设备本地 |
|
数据持久性 |
应用卸载时数据会被清除 |
|
异步操作 |
所有读写操作均为异步( |
|
跨平台一致性 |
自动适配 Android/iOS/Web/桌面端 |
三、使用步骤
1. 添加依赖
# pubspec.yaml
dependencies:
# 存储键值对数据的轻量级解决方案,适用于保存用户设置、偏好等小型数据。
shared_preferences: ^2.5.4
2. 导入包
import 'package:shared_preferences/shared_preferences.dart';
3. 获取实例
final prefs = await SharedPreferences.getInstance();
4. 数据操作方法
|
操作类型 |
方法签名 |
示例 |
|
写入数据 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
读取数据 |
|
|
|
删除数据 |
|
|
|
清空数据 |
|
|
四、工程化封装
在 Flutter 开发中,shared_preferences (SP) 几乎是每个项目的标配,但在实际搬砖过程中,如果直接在业务层满大街写 SharedPreferences.getInstance(),不仅代码显得臃肿,后期维护 Key 值更是一场灾难。今天分享一套我在项目中沉淀的 SP 封装方案,通过 工具类化 和 常量化,实现逻辑解耦。
4.1 为什么要封装?
很多新手喜欢在 initState 里异步获取 SP 实例,这种做法有两个明显的弊端:
-
代码重复:每个页面都要写一遍异步等待。
-
硬编码:
prefs.getString('user_token')里的字符串一旦写错一个字母,排查起来非常头疼。
我们的目标是:全局初始化一次,到处同步调用,Key 值统一管理。
4.2 统一键值管理:SPKeys
首先,新建 sp_keys.dart,我们利用私有构造函数,确保 Key 值只在一个地方定义。
/// Description: 定义存储键值对的键
/// CreateDate: 2025/12/22 11:31
/// Author: agg
class SPKeys {
SPKeys._(); // 闭合构造函数,防止被实例化
static const String userToken = 'user_token';
static const String themeMode = 'theme_mode';
static const String userInfo = 'user_info';
}
4.3 工具类实现:SPUtils
在 sp_utils.dart 中,我们引入 late 关键字,通过在应用启动时预加载,将后续的 IO 操作转化为类似同步的调用。
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
///
/// Description: 存储键值对数据工具类
/// CreateDate: 2025/12/22 9:54
/// Author: agg
///
class SPUtils {
// 使用 late 关键字,如果未初始化就调用会直接报错,方便开发者定位
static late SharedPreferences _prefs;
/// 初始化:在 main.dart 中 await SPUtils.init()
static Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}
// ==================== 核心方法 ====================
/// 保存数据
/// 支持 String, int, double, bool, List<String>
/// 以及可以通过 jsonEncode 转换的 Map 或 Object
static Future<bool> set(String key, dynamic value) {
if (value is String) return _prefs.setString(key, value);
if (value is int) return _prefs.setInt(key, value);
if (value is bool) return _prefs.setBool(key, value);
if (value is double) return _prefs.setDouble(key, value);
if (value is List<String>) return _prefs.setStringList(key, value);
// 如果是 Map 或自定义对象,转为 json 字符串存储
return _prefs.setString(key, jsonEncode(value));
}
static String getString(String key, {String defaultValue = ''}) {
return _prefs.getString(key) ?? defaultValue;
}
static int getInt(String key, {int defaultValue = 0}) {
return _prefs.getInt(key) ?? defaultValue;
}
static bool getBool(String key, {bool defaultValue = false}) {
return _prefs.getBool(key) ?? defaultValue;
}
static double getDouble(String key, {double defaultValue = 0.0}) {
return _prefs.getDouble(key) ?? defaultValue;
}
static List<String> getStringList(
String key, {
List<String> defaultValue = const [],
}) {
return _prefs.getStringList(key) ?? defaultValue;
}
/// 获取复杂对象 (Map 或 List)
/// 读取后需手动转换类型: Map user = SPUtils.getObject('user');
static dynamic getObject(String key) {
String? jsonStr = _prefs.getString(key);
if (jsonStr == null || jsonStr.isEmpty) return null;
try {
return jsonDecode(jsonStr);
} catch (e) {
print("SPUtils getObject error: $e");
return null;
}
}
// ==================== 工具方法 ====================
static bool containsKey(String key) => _prefs.containsKey(key);
static Future<bool> remove(String key) => _prefs.remove(key);
static Future<bool> clear() => _prefs.clear();
}
4.4 在项目中使用
-
入口预装载 在 main.dart 的 main 函数中,先确保 Flutter 引擎初始化,然后加载 SP。
void main() async { // 必须调用,确保与原生层交互正常 WidgetsFlutterBinding.ensureInitialized(); // 预装载 SP,耗时极短,但收益巨大 await SPUtils.init(); runApp(const MyApp()); } -
业务逻辑层调用 在任何 Widget 或 Controller 里读写数据,都不再需要 await 获取实例。
// 存储 Token
SPUtils.set(SPKeys.userToken, "ey...123");
// 存储复杂的用户信息
Map<String, dynamic> user = {"name": "agg", "age": 18};
SPUtils.set(SPKeys.userInfo, user);
// 获取数据
String token = SPUtils.getString(SPKeys.userToken);
4.5 小结
-
同步化体验:虽然 SP 的原生 API 是异步的,但通过在
main函数预加载实例,我们可以像操作内存变量一样操作本地持久化数据。
-
安全提示:由于使用了
late,如果在init()还没完成时就强行调用读取方法,程序会 Crash,所以务必在runApp之前完成初始化。
-
选型建议:SP 适合存储小体量的配置信息(如登录态、主题颜色、引导页状态),如果是大批量的结构化数据,建议使用
Hive或SQFlite。
五、总结
SharedPreferences 是 Flutter 生态中最基础的持久化方案,具有上手简单、跨平台兼容的优势,适用于存储小型、非敏感的键值对数据。
更多推荐



所有评论(0)