news 2026/4/15 16:03:18

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/10 16:47:07

深入理解上拉电阻:系统学习其偏置电流路径

上拉电阻的“小身材大智慧”&#xff1a;从悬空引脚到系统稳定的底层逻辑你有没有遇到过这样的情况——明明代码写得没问题&#xff0c;MCU却莫名其妙重启&#xff1f;或者按键按一下触发好几次&#xff1f;又或者IC通信时不时丢数据&#xff0c;示波器一看&#xff0c;上升沿“…

作者头像 李华
网站建设 2026/4/5 19:27:41

LangFlow SkyWalking接入指南发布

LangFlow 与 SkyWalking 的融合&#xff1a;构建可观测的 AI 工作流 在 AI 应用快速落地的今天&#xff0c;一个常见的困境浮出水面&#xff1a;如何让复杂的语言模型工作流既“搭得快”&#xff0c;又“看得清”&#xff1f;开发团队可以借助图形化工具迅速搭建起智能体流程&a…

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

LangFlow SmokePing监测延迟波动

LangFlow 与 SmokePing&#xff1a;构建可观察的 AI 工作流 在当今快速演进的 AI 应用生态中&#xff0c;一个日益凸显的问题是——我们能否既快速搭建智能系统&#xff0c;又能清晰“看见”它的运行状态&#xff1f;尤其是在使用 LangChain 构建复杂代理或自动化流程时&#x…

作者头像 李华
网站建设 2026/4/12 16:29:15

LangFlow钉钉/企业微信机器人集成方案

LangFlow与企业通讯平台的智能集成实践 在企业数字化转型加速的今天&#xff0c;如何让大语言模型&#xff08;LLM&#xff09;真正“落地”到员工的日常工作中&#xff0c;成为了一个关键命题。很多公司虽然引入了AI技术&#xff0c;但最终只停留在演示PPT里——因为员工根本不…

作者头像 李华
网站建设 2026/4/15 12:58:28

工业控制PCB布局设计:抗干扰策略深度剖析

工业控制PCB布局设计&#xff1a;从“能用”到“可靠”的跨越在工厂车间里&#xff0c;一台PLC突然无故重启&#xff0c;温度采集值跳变几度&#xff1b;一条自动化产线上的伺服驱动器频繁报错&#xff0c;却查不出硬件故障。这些看似玄学的问题&#xff0c;背后往往藏着同一个…

作者头像 李华
网站建设 2026/4/11 21:36:36

LangFlow GitHub Actions联动实现自动部署

LangFlow 与 GitHub Actions 联动实现自动部署 在 AI 应用开发日益普及的今天&#xff0c;一个核心挑战逐渐浮现&#xff1a;如何让非专业开发者也能快速构建、调试并部署基于大语言模型&#xff08;LLM&#xff09;的工作流&#xff1f;传统的代码驱动方式虽然灵活&#xff0c…

作者头像 李华