Flutter解析SharedPreferences数据报FormatException异常如何解决
问题产生原因
FormatException: Unexpected character (at character 3) 报错的核心原因是你从SharedPreferences中取出的value不是合法的标准JSON格式字符串,非空不代表格式符合解析要求,90%以上的同类问题都是以下情况导致:
- 存值时没有调用
jsonEncode把结构化的List/Map对象转成标准JSON字符串,直接把Dart对象的toString()返回值存进了存储。比如List<Map>直接调用toString()得到的结果是[{key: value}]格式:键名没有双引号包裹、字符串值也没有双引号,不符合JSON语法规范,jsonDecode从第3个字符开始就识别不了格式,刚好对应你报错的字符位置。 - 存值时字符串头部混入了不可见控制字符、多余前缀符号,破坏了JSON结构。
- 原有代码里的
as List<Map>强转存在类型安全隐患:jsonDecode返回的列表默认是List<dynamic>类型,元素为Map<String, dynamic>,直接硬转在部分场景下会触发隐式类型错误。
修复方案
- 先排查原始存储值的真实格式
不要只判断值是否非空,先打印取出值的完整内容和类型,确认格式问题:getIt<Storage>().get("data_${id}").then((value) { print("原始存储内容:$value"); print("存储值类型:${value.runtimeType}"); // 后续逻辑 }); - 修正存值逻辑
所有结构化数据写入SharedPreferences前,必须用jsonEncode转成标准JSON字符串,禁止直接存储对象toString()的结果:// 正确存值示例 final String saveStr = jsonEncode(yourTargetListData); getIt<Storage>().set("data_${id}", saveStr); - 替换为类型安全的解析逻辑,增加兜底处理
避免硬转类型,对解析失败、格式不匹配的场景做空列表兜底,防止页面崩溃:getIt<Storage>().get("data_${id}").then((value) { try { // 空值、非字符串、空字符串直接兜底 if (value == null || value is! String || value.trim().isEmpty) { myNotifier.value = <Map<String, dynamic>>[]; return; } final dynamic decodeResult = jsonDecode(value); // 校验解码结果为列表类型后再做转换 if (decodeResult is List) { myNotifier.value = decodeResult .map((item) => Map<String, dynamic>.from(item as Map)) .toList(); } else { myNotifier.value = <Map<String, dynamic>>[]; } } catch (e) { print("解析异常:$e"); myNotifier.value = <Map<String, dynamic>>[]; // 历史脏数据可以直接清除对应key,后续重新写入正确格式数据 // getIt<Storage>().remove("data_${id}"); } }); - 本地已经存了历史脏数据的话,第一次运行修复逻辑时可以直接删除对应key,后续业务流程重新写入正确格式的内容即可。
内容的提问来源于stack exchange,提问作者user17838882
相关产品推荐
相关产品推荐

