news 2026/4/23 13:17:41

Flutter 数据存储之 SharedPreferences 键值对存储

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter 数据存储之 SharedPreferences 键值对存储

目录

一、简介

二、核心概念

三、使用步骤

1. 添加依赖

2. 导入包

3. 获取实例

4. 数据操作方法

四、工程化封装

4.1 为什么要封装?

4.2 统一键值管理:SPKeys

4.3 工具类实现:SPUtils

4.4 在项目中使用

4.5 小结

五、总结


一、简介

SharedPreferencesFlutter官方提供的轻量级本地数据存储方案,适用于保存用户配置、登录状态、简单设置等键值对(Key-Value)数据。

其底层基于平台原生实现(Android 的SharedPreferences和 iOS 的NSUserDefaults),具有操作简单、读写高效的特点。

二、核心概念

特性

说明

数据类型支持

intdoubleboolStringList<String>

存储位置

自动持久化到设备本地

数据持久性

应用卸载时数据会被清除

异步操作

所有读写操作均为异步(Future

跨平台一致性

自动适配 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. 数据操作方法

操作类型

方法签名

示例

写入数据

setInt(String key, int value)

prefs.setInt('age', 25);

setDouble(String key, double value)

prefs.setDouble('price', 9.99);

setBool(String key, bool value)

prefs.setBool('isDark', true);

setString(String key, String value)

prefs.setString('name', 'Tom');

setStringList(String key, List<String> value)

prefs.setStringList('tags', ['a','b']);

读取数据

get(String key)/getInt()/getBool()

prefs.getInt('age') ?? 0;

删除数据

remove(String key)

prefs.remove('tempData');

清空数据

clear()

prefs.clear();

四、工程化封装

在 Flutter 开发中,shared_preferences(SP) 几乎是每个项目的标配,但在实际搬砖过程中,如果直接在业务层满大街写SharedPreferences.getInstance(),不仅代码显得臃肿,后期维护 Key 值更是一场灾难。今天分享一套我在项目中沉淀的 SP 封装方案,通过 工具类化 和 常量化,实现逻辑解耦。

4.1 为什么要封装?

很多新手喜欢在initState里异步获取 SP 实例,这种做法有两个明显的弊端:

  1. 代码重复:每个页面都要写一遍异步等待。

  2. 硬编码: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 在项目中使用

  1. 入口预装载 在 main.dart 的 main 函数中,先确保 Flutter 引擎初始化,然后加载 SP。

    void main() async { // 必须调用,确保与原生层交互正常 WidgetsFlutterBinding.ensureInitialized(); // 预装载 SP,耗时极短,但收益巨大 await SPUtils.init(); runApp(const MyApp()); }
  2. 业务逻辑层调用 在任何 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 适合存储小体量的配置信息(如登录态、主题颜色、引导页状态),如果是大批量的结构化数据,建议使用HiveSQFlite

五、总结

SharedPreferences是 Flutter 生态中最基础的持久化方案,具有上手简单、跨平台兼容的优势,适用于存储小型、非敏感的键值对数据。

官方文档:SharedPreferences API

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 10:32:35

25、Exchange Server 2007灾难恢复全攻略

Exchange Server 2007灾难恢复全攻略 在企业的日常运营中,Exchange Server 2007扮演着至关重要的角色,它负责着邮件的收发、存储等核心任务。然而,硬件故障、数据库损坏等问题随时可能导致服务器出现故障,影响企业的正常运转。因此,掌握Exchange Server 2007的灾难恢复方…

作者头像 李华
网站建设 2026/4/23 11:35:00

WinDbg内存转储分析:一文说清蓝屏排查流程

WinDbg内存转储分析实战&#xff1a;从蓝屏崩溃到根因定位的完整路径 你有没有遇到过这样的场景&#xff1f; 一台关键业务服务器突然黑屏重启&#xff0c;事件日志里只留下一句冷冰冰的“ The computer has rebooted from a bugcheck. ”——系统因严重错误重启。没有明确…

作者头像 李华
网站建设 2026/4/18 12:47:21

时序逻辑电路功耗优化:低功耗设计实践指南

时序逻辑电路功耗优化&#xff1a;从原理到实战的低功耗设计之道你有没有遇到过这样的问题&#xff1f;芯片明明功能跑通了&#xff0c;时序也收敛了&#xff0c;可一测功耗——待机电流高得离谱&#xff0c;电池撑不过半天。尤其在智能手表、无线传感器这类靠纽扣电池“续命”…

作者头像 李华
网站建设 2026/4/22 22:23:39

多电源域硬件电路设计图解说明

多电源域设计实战&#xff1a;从原理到避坑&#xff0c;一文讲透嵌入式系统供电架构你有没有遇到过这样的场景&#xff1f;一个看似简单的MCU系统&#xff0c;上电后ADC读数跳动剧烈&#xff1b;传感器偶尔失联&#xff0c;重启又恢复正常&#xff1b;低功耗模式下电流不降反升…

作者头像 李华
网站建设 2026/4/23 11:37:23

工业自动化控制器PCB设计全流程完整指南

工业自动化控制器PCB设计实战全解&#xff1a;从零到量产的每一步 在智能制造的浪潮中&#xff0c;工业自动化控制器早已不再是简单的继电器逻辑组合。它作为产线的“大脑”&#xff0c;承载着数据采集、实时控制、通信互联等核心任务。而这一切功能实现的基础&#xff0c;正是…

作者头像 李华
网站建设 2026/4/8 5:26:31

如何将go项目部署到docker上

一、上传你的go项目如&#xff1a;这是我的项目目录可以直接进行拖拽二、在虚拟机上创建这样的目录结构~/GoProJect/pro1/test01 我这样是为了确保导入包的路径正确&#xff0c;确保项目能正常运行。然后就把common\server\user\vin 这四个文件拖到 test01目录下&#xff0c;还…

作者头像 李华