Flutter基于GetX与GetStorage读取本地列表时触发类型不匹配报错
核心问题根因
报错本质是存储读取时的类型不匹配,和GetX页面栈的路由逻辑没有直接关系,具体是两个叠加的问题导致的:
- 写入GetStorage时,没有将自定义的
ShoppingList实例手动转换为可被Storage序列化的Map<String, dynamic>结构,直接把内存中的对象列表存入了本地存储。 - 从Storage读取数据时,代码默认列表里的元素全是
Map<String, dynamic>结构,实际因为之前写入的是未转换的ShoppingList对象,调用ShoppingList.fromjson()时传入了类型不匹配的参数,直接触发类型报错。
这个报错的复现逻辑和你的操作完全匹配:首次打开页面时直接使用内存中的对象,不触发Storage读取逻辑所以不报错;退出页面时因为写入的是未转换的原始对象,本地存储的格式不符合预期;再次进入页面时执行Storage读取流程,传入类型不匹配的参数就触发了崩溃。
分步修复方案
- 第一步:补全
ShoppingList类的序列化逻辑
原代码的toJson方法漏了done字段的序列化,就算解决了类型不匹配问题,也会导致任务完成状态永久丢失。修正后的类定义如下:class ShoppingList { String text; bool done; ShoppingList({required this.text, this.done = false}); // 修正命名为标准的fromJson,避免拼写歧义 factory ShoppingList.fromJson(Map<String, dynamic> json) => ShoppingList( text: json['text'] as String, done: json['done'] as bool, ); Map<String, dynamic> toJson() { final Map<String, dynamic> data = <String, dynamic>{}; data['text'] = text; data['done'] = done; // 补上遗漏的done字段序列化 return data; } } - 第二步:修正存储写入逻辑
GetStorage仅支持基础类型、嵌套Map/List结构的持久化,无法直接序列化自定义Dart类对象,写入时必须手动将每个ShoppingList实例转为Map结构再存入:
在新增条目、修改完成状态、删除条目等列表变更的位置,调用这个同步方法,保证存入Storage的永远是纯Map结构的列表。// 控制器内新增存储同步方法 void syncDataToStorage() { // 将所有购物项转成Map结构生成可存储的列表 final List<Map<String, dynamic>> storageMapList = shoppings .map((item) => item.toJson()) .toList(); GetStorage().write('shoppings', storageMapList); } - 第三步:增强读取逻辑的健壮性
原控制器的onInit存在两个问题:没有调用父类生命周期方法、没有做异常类型过滤,容易因为历史脏数据触发崩溃。修正后的控制器代码如下:class ShoppingListController extends GetxController { // 明确声明RxList类型,避免类型推断错误 final RxList<ShoppingList> shoppings = <ShoppingList>[].obs; @override void onInit() { super.onInit(); // 必须调用父类onInit完成生命周期初始化 final List? storedShoppings = GetStorage().read<List>('shoppings'); if (storedShoppings != null) { // 过滤掉列表中非Map结构的脏数据,避免类型报错 shoppings.value = storedShoppings .whereType<Map<String, dynamic>>() .map((e) => ShoppingList.fromJson(e)) .toList(); } } // 示例:新增购物项的方法,变更后自动同步存储 void addItem(String content) { shoppings.add(ShoppingList(text: content)); syncDataToStorage(); } }
额外注意事项
- 不要直接将自定义类实例直接传入
GetStorage().write(),必须手动完成对象到Map的转换,否则下次读取必然出现类型异常。 - 原代码中给响应式列表重新赋值的写法(
shoppings = xxx.toList().obs)虽然能运行,但更推荐通过shoppings.value = xxx的方式赋值,避免出现响应式绑定失效的问题。 - 本地存储的key要保持全局唯一,避免和其他存储值混淆。
内容的提问来源于stack exchange,提问作者SimoneR
相关产品推荐
相关产品推荐

