news 2026/6/23 23:08:21

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/6/23 14:46:20

新手教程:使用WinDbg分析x64蓝屏DMP文件

从蓝屏废墟中重建真相&#xff1a;手把手教你用 WinDbg 解剖 x64 系统崩溃 你有没有遇到过这样的场景&#xff1f; 一台关键服务器突然黑屏&#xff0c;重启后留下一个神秘的 MEMORY.DMP 文件&#xff1b; 或是某台开发机频繁蓝屏&#xff0c;错误代码一闪而过&#xff0c…

作者头像 李华
网站建设 2026/6/23 18:58:33

LangFlow Cacti流量图展示网络吞吐量

LangFlow 与性能可视化&#xff1a;构建可度量的 AI 工作流 在今天&#xff0c;大语言模型&#xff08;LLM&#xff09;已经不再是实验室里的概念玩具&#xff0c;而是正快速渗透进客服系统、智能助手、代码生成乃至企业决策支持等真实场景。但随之而来的问题也愈发明显&#x…

作者头像 李华
网站建设 2026/6/23 16:59:45

面向工业控制的模拟电子技术基础入门必看指南

面向工业控制的模拟电子技术入门&#xff1a;从传感器到执行器的完整信号链解析在智能制造与工业4.0浪潮席卷全球的今天&#xff0c;自动化系统正变得越来越“聪明”。然而&#xff0c;再先进的PLC、再强大的边缘AI处理器&#xff0c;如果无法准确感知物理世界的变化——温度漂…

作者头像 李华
网站建设 2026/6/23 1:45:58

65、利用组策略管理硬件访问与打印机分配全攻略

利用组策略管理硬件访问与打印机分配全攻略 1. 组策略中硬件禁用与启用选项的缘由 在组策略里,设备扩展项有禁用和启用两个选项。借助组策略对象(GPO)过滤或组策略首选项扩展的项目级别目标设定,就能灵活决定谁的哪些硬件该启用,哪些该禁用。比如,除了实验室技术员需要…

作者头像 李华
网站建设 2026/6/23 17:03:33

f1系列替换下载失败

在 STM32F1 系列中&#xff0c; startup_stm32f10xxx_ld.s 、 startup_stm32f10xxx_md.s 、 startup_stm32f10xxx_hd.s 这几个启动文件的区别主要在于 芯片的 Flash 容量&#xff08;密度&#xff09;&#xff0c;不同密度的芯片对应不同的启动文件。- ld &#xff08;Low-de…

作者头像 李华
网站建设 2026/6/23 16:54:12

LangFlow内置模板库发布,涵盖常见AI应用场景

LangFlow 内置模板库发布&#xff0c;开启AI应用可视化开发新纪元 在大模型技术席卷各行各业的今天&#xff0c;越来越多团队希望快速构建智能问答、文档处理、自动化代理等AI系统。然而现实是&#xff1a;即便有了LangChain这样强大的框架&#xff0c;开发者仍需面对复杂的API…

作者头像 李华