Flutter调用API获取数据后如何保存到SharedPreferences?
前置准备
- 首先在项目
pubspec.yaml中添加SharedPreferences依赖,执行flutter pub get完成安装:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2
注:版本号可替换为pub平台的最新稳定版本,插件内部已做全平台兼容,无需额外配置原生端权限。
封装本地存储工具类
为避免各处重复编写存储逻辑,统一封装操作方法。由于SharedPreferences仅支持存储基础类型、字符串、字符串列表,存储结构化用户数据时需要先转成JSON字符串:
import 'package:shared_preferences/shared_preferences.dart'; import 'dart:convert'; class SPUtil { // 定义存储key常量,避免硬编码写错 static const String _userInfoKey = "cached_user_info"; static const String _loginFlagKey = "is_logged_in"; // 保存全量用户信息 static Future<void> cacheUserInfo(Map<String, dynamic> userData) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString(_userInfoKey, jsonEncode(userData)); await prefs.setBool(_loginFlagKey, true); } // 读取本地缓存的用户信息 static Future<Map<String, dynamic>?> getCachedUserInfo() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); final String? userJsonStr = prefs.getString(_userInfoKey); if (userJsonStr == null || userJsonStr.isEmpty) return null; return jsonDecode(userJsonStr) as Map<String, dynamic>; } // 退出登录时清除本地用户缓存 static Future<void> clearUserCache() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.remove(_userInfoKey); await prefs.setBool(_loginFlagKey, false); } // 按需单独存储高频使用字段,比如用户ID static Future<void> cacheUserId(String userId) async { final SharedPreferences prefs = await SharedPreferences.getInstance(); await prefs.setString("cached_user_id", userId); } static Future<String?> getCachedUserId() async { final SharedPreferences prefs = await SharedPreferences.getInstance(); return prefs.getString("cached_user_id"); } }
修改现有登录逻辑
在原有登录校验通过的分支里,页面跳转前插入存储逻辑即可,修改后的登录方法代码如下:
Future<Loginmodel?> login() async { if (passwordController.text.isNotEmpty && nameController.text.isNotEmpty) { var response = await http.post( Uri.parse('XYZ'), headers: {"Content-Type": "application/json"}, body: jsonEncode({ 'UserName': nameController.text, 'Password': passwordController.text, 'DeviceToken': '', 'DeviceType': '' }) ); if (response.statusCode == 200) { var data = jsonDecode(response.body); if (data['data']['UserID'] == null) { ScaffoldMessenger.of(context) .showSnackBar(const SnackBar(content: Text("账号或密码错误"))); } else { // 校验通过后先持久化用户数据,必须加await等待存储完成 await SPUtil.cacheUserInfo(data['data']); await SPUtil.cacheUserId(data['data']['UserID'].toString()); // 存储完成后再做跳转和提示 if (context.mounted) { Navigator.push( context, MaterialPageRoute(builder: (context) => const Homescreen()) ); ScaffoldMessenger.of(context) .showSnackBar(const SnackBar(content: Text("登录成功"))); } } } } else { ScaffoldMessenger.of(context) .showSnackBar(const SnackBar(content: Text("输入框不能为空"))); } return null; }
读取缓存示例
后续业务中需要用到用户信息时,直接调用封装好的方法即可:
// 比如首页初始化时读取本地用户信息 @override void initState() { super.initState(); loadLocalUserInfo(); } void loadLocalUserInfo() async { Map<String, dynamic>? userInfo = await SPUtil.getCachedUserInfo(); if (userInfo != null) { print("用户名:${userInfo['UserName']}"); print("手机号:${userInfo['MobileNo']}"); print("邮箱:${userInfo['Email']}"); } }
注意点
- 所有SharedPreferences的写入操作都是异步的,必须加
await等待执行完成,否则可能出现跳转页面后读取不到刚存数据的问题 - 不要把密码、支付密钥这类高敏感信息存在SharedPreferences中,普通用户资料、登录状态这类非敏感数据存储没有问题
- 页面跳转前建议加
context.mounted判断,避免异步操作完成后组件已经销毁导致的报错 - 退出登录时一定要调用
SPUtil.clearUserCache()清除本地缓存,避免多账号切换时数据混乱
内容的提问来源于stack exchange,提问作者Panchal Ravi
相关产品推荐
相关产品推荐

