Flutter中SharedPreferences存储数组后无法单独读取用户信息子项
问题根因
SharedPreferences 仅支持存储基础类型(字符串、数字、布尔、字符串列表),不支持直接存储Dart的Map、List这类结构化对象。你当前的实现应该是直接把接口返回的响应体/用户数组未做标准序列化就存入,存进去的内容要么是格式不规范的字符串,要么存的时候就没正确保留字段结构,自然无法单独读取内部字段。
正确实现步骤
- 第一步:接口返回响应后,先通过
dart:convert内置的jsonDecode()方法,把JSON格式的响应字符串转成可操作的Dart结构化对象(Map/List),不要直接拿原始响应内容存储。 - 第二步:根据业务场景选存储方式:
- 轻量场景:按需单独存要用到的独立字段,比如用户名、用户ID、认证token,调用对应类型的set方法存,读取时直接按key取值,逻辑最简单不容易出错。
- 字段较多的场景:把处理好的当前登录用户对象,通过
jsonEncode()序列化成标准JSON字符串再存储,读取时拿到字符串后再用jsonDecode()转回Map结构,就能按需取任意字段。
- 第三步:如果接口返回的是用户信息数组,先从数组中筛选/定位到当前登录的对应用户对象再存储,不要直接把整个数组存完就不管,读取时容易出现下标越界、取错用户的问题。
代码示例
首先在用到的文件中导入必须的依赖:
import 'dart:convert'; import 'package:shared_preferences/shared_preferences.dart';
登录请求成功后的存储逻辑(替换你原来的存值代码即可):
// 解析接口返回的原始响应体 final responseData = jsonDecode(resposta.body); // 按你实际接口的结构取当前登录用户对象 // 如果接口直接返回用户对象就直接转Map,如果返回数组就先转List再取下标对应的用户 // 示例:假设接口返回结构为 {"code":0, "data":{"token":"xxx", "user":{"id":1, "name":"张三"}}} final String authToken = responseData['data']['token']; final Map<String, dynamic> currentUser = responseData['data']['user']; final prefs = await SharedPreferences.getInstance(); // 存储方式1:单独存常用字段,读取最方便 await prefs.setString('auth_token', authToken); await prefs.setInt('user_id', currentUser['id']); await prefs.setString('user_name', currentUser['name']); // 存储方式2:存完整用户信息(适合字段多的场景,二选一即可) await prefs.setString('current_user_full_info', jsonEncode(currentUser));
其他页面读取用户信息的逻辑:
final prefs = await SharedPreferences.getInstance(); // 对应存储方式1的读取 String userName = prefs.getString('user_name') ?? '未登录'; int userId = prefs.getInt('user_id') ?? 0; String token = prefs.getString('auth_token') ?? ''; // 对应存储方式2的读取 String? userInfoStr = prefs.getString('current_user_full_info'); if(userInfoStr != null){ Map<String, dynamic> userInfo = jsonDecode(userInfoStr); // 按需取任意字段即可 String userName = userInfo['name'] ?? ''; String userPhone = userInfo['phone'] ?? ''; }
常见踩坑点
- 不要直接把Dart原生Map/List对象传给setString方法,Dart默认的对象
toString()输出不是标准JSON格式,后续解码会直接报错,序列化必须用jsonEncode方法。 - 存值前先打印解析后的用户对象,确认字段名和接口返回的完全一致,比如接口返回字段是
username你写name,取出来肯定是null。 - 调试阶段如果之前存了格式错误的脏数据,可以先调用
prefs.clear()清空本地存储,或者卸载重装App再测试,避免旧数据干扰结果。
内容的提问来源于stack exchange,提问作者Gabriel G Maiworm
相关产品推荐
相关产品推荐

