Flutter使用SharedPreferences保存DateTime遇序列化及空类型错误求助
问题原因
你遇到的两个异常本质都是DateTime无法直接JSON序列化/反序列化导致的:
type 'Null' is not a subtype of type 'DateTime':加载数据时,jsonDecode无法将保存的DateTime对象还原为有效DateTime实例,返回Null,与Shopping类的非空date字段类型不匹配。Converting object to an encodable object failed: Instance of 'Shopping':保存数据时,Shopping的toJson方法直接返回DateTime实例,而jsonEncode不支持原生DateTime类型的序列化。
解决方案
通过将DateTime转换为JSON支持的数字类型(毫秒时间戳)来实现序列化与反序列化,同时优化数据加载逻辑。
1. 修改Shopping类,实现正确的序列化/反序列化
import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; class Shopping { String item; int price; DateTime date; Shopping({required this.item, required this.price, required this.date}); // 序列化:将DateTime转为毫秒时间戳(JSON支持数字类型) Map<String, dynamic> toJson() { return { 'item': item, 'price': price, 'date': date.millisecondsSinceEpoch, }; } // 反序列化:从毫秒时间戳转回DateTime factory Shopping.fromJson(Map<String, dynamic> json) { return Shopping( item: json['item'] ?? '', price: json['price'] ?? 0, date: DateTime.fromMillisecondsSinceEpoch(json['date'] ?? 0), ); } }
2. 修改ItemData的loadData方法,使用fromJson构造函数
class ItemData extends ChangeNotifier { List<Shopping> listOfItem = []; // ... 其他方法保持不变 ... loadData() async { SharedPreferences pref = await SharedPreferences.getInstance(); if (pref.getStringList('itemList') != null) { List<String> tempList = pref.getStringList('itemList')!; for (int i = 0; i < tempList.length; i++) { Map<String, dynamic> temp = jsonDecode(tempList[i]); // 使用fromJson构造Shopping实例,避免类型不匹配 addItem(Shopping.fromJson(temp)); } } } }
3. 优化AddItem页面的日期获取逻辑
将DateTime的获取移到按钮点击事件内,避免build方法重复创建实例,同时确保保存操作完成后再返回上一页:
CupertinoButton( // ... 其他属性保持不变 ... onPressed: () async { // 点击时才获取当前时间 DateTime date = DateTime.now(); Shopping newItem = Shopping( item: userInputItem.text, price: int.parse(userInputPrice.text), date: date, ); provider.addItem(newItem); // 等待保存完成再返回,避免数据未写入就退出 await provider.saveData(); Navigator.pop(context); }, ),
关键说明
- 毫秒时间戳是JSON原生支持的数字类型,能被jsonEncode/jsonDecode正确处理,避免序列化异常。
- 使用
factory Shopping.fromJson统一处理反序列化逻辑,同时通过??运算符处理可能的空值,防止类型转换失败。 - 保存数据时添加
await,确保SharedPreferences完成写入操作后再执行页面跳转,避免数据丢失。
内容的提问来源于stack exchange,提问作者Abdulhadi Naser
相关产品推荐
相关产品推荐

