Flutter SharedPreferences加载List报Null非List<Row>子类型异常
问题根因
报错type 'Null' is not a subtype of type 'List<Row>'的直接原因是代码预期获取非空的List<Row>类型值,实际拿到了null,对应到你的场景有四个常见触发点:
- SharedPreferences的写入操作是异步的,如果调用写入方法时没有加
await等待执行完成就触发热重启,数据根本没有落到本地存储,读取对应key时会直接返回null Data类的fromJson构造方法对chatMessages字段做了非空强转,没有做null兼容,只要JSON中不存在该字段、或者字段值为null,强转逻辑就会抛出类型错误- SharedPreferences本身不支持直接存储自定义类型的List,如果你存的时候没有把对象先转成JSON字符串,直接传入
List<Row>类型,存储逻辑会执行失败,读取时自然拿到null - 如果你用的
Row是Flutter框架自带的Widget组件,它本身不支持JSON序列化,直接存储Widget实例必然会失败。
修复方案
按以下步骤调整代码即可解决:
- 修正写入逻辑,必须等待写入完成再执行后续操作,复杂对象先转成JSON字符串再存储
// 写入逻辑示例 final prefs = await SharedPreferences.getInstance(); // 先把数据对象转成JSON字符串,不要直接存自定义类/Widget实例 final String saveStr = jsonEncode(Data( chatMessages: yourMessageList, // 这里的列表元素要是可序列化的普通数据类,不能是Widget ).toJson()); // 必须加await等待写入完成,否则热重启/杀进程可能丢数据 await prefs.setString('data_cache_key', saveStr);
- 修正
fromJson构造方法,给所有字段加空值兜底,不要直接做非空强转
factory Data.fromJson(Map<String, dynamic> json) { return Data( // 核心:字段先按可空类型解析,null时给空数组做兜底 chatMessages: (json['chatMessages'] as List<dynamic>?) ?.map((item) => ChatMessageItem.fromJson(item as Map<String, dynamic>)) .toList() ?? const [], // 其余字段都按照相同逻辑加空兜底即可 ); }
注意:聊天列表项要抽成普通数据类存储,渲染时再根据数据生成Row组件,不要直接把Row组件当数据存。
- 修正读取逻辑,兼容本地无缓存的场景
// 读取逻辑示例 final prefs = await SharedPreferences.getInstance(); Data cacheData; final String? cacheStr = prefs.getString('data_cache_key'); if (cacheStr != null) { // 本地有缓存时再做反序列化 cacheData = Data.fromJson(jsonDecode(cacheStr) as Map<String, dynamic>); } else { // 无缓存时初始化空数据,避免null cacheData = Data(chatMessages: const []); }
补充说明:热重启会重置Flutter应用的内存状态,但不会清空SharedPreferences的本地持久化文件,只要写入逻辑正确等await执行完成,热重启后是可以正常读到数据的。
验证方法
改完后按以下顺序验证即可:
- 写入测试数据后,确认
setString的异步方法执行完成,再触发热重启,检查列表加载是否正常 - 手动清除应用数据/删除对应缓存key,冷启动应用,确认不会崩溃,正常显示空列表
- 存入测试数据后杀掉应用进程重新打开,确认列表数据正常加载
内容的提问来源于stack exchange,提问作者CastoldiG
相关产品推荐
相关产品推荐

