Flutter中SharedPreferences结合Provider加载购物车数据失败问题
问题分析
- Provider实例不匹配:加载时新建的
Count countObject和Provider注入到应用中的实例不是同一个,导致加载的数据无法同步到购物车状态。 - 数据保存格式错误:保存时把所有购物车项合并成单个字符串后添加到列表,加载时却按单个购物车项解析,导致数据分割错乱。
- initState中获取Provider的时机问题:initState阶段context未完全就绪,直接调用
Provider.of可能出现异常或无法获取正确实例。
修复方案
1. 修正数据保存逻辑
将每个购物车项单独转为字符串,直接保存为字符串列表,避免合并导致的解析错误:
// 修正后的保存订单代码 final prefs = await SharedPreferences.getInstance(); // 每个购物车项单独生成字符串,转为列表保存 final orderItems = cartItems.map((item) { return '${item.name},${item.count},${item.price},${item.imagePath}'; }).toList(); await prefs.setStringList('orders', orderItems);
2. 修正数据加载逻辑
等待Widget构建完成后,获取Provider中的真实Count实例,将加载的数据同步到该实例中:
@override void initState() { super.initState(); // 等待Widget渲染完成后再执行加载 WidgetsBinding.instance.addPostFrameCallback((_) { _loadOrders(); }); } Future<void> _loadOrders() async { final prefs = await SharedPreferences.getInstance(); final orderItems = prefs.getStringList('orders') ?? []; // 获取Provider中正在使用的Count实例 final countProvider = Provider.of<Count>(context, listen: false); // 清空原有数据(根据业务需求选择是否保留) countProvider.clearCart(); for (String itemStr in orderItems) { List<String> details = itemStr.split(','); // 增加格式校验,避免解析异常 if (details.length != 4) continue; countProvider.addItem( details[0], int.parse(details[1]), double.parse(details[2]), details[3], ); } }
3. 完善Count类的核心方法
确保Count类能正确维护购物车数据,提供必要的增删清方法:
class Count extends ChangeNotifier { List<CartItem> cartItems = []; void addItem(String name, int count, double price, String imagePath) { final existingItem = cartItems.firstWhere( (item) => item.name == name, orElse: () => CartItem(name: '', count: 0, price: 0, imagePath: ''), ); if (existingItem.name.isNotEmpty) { existingItem.count += count; } else { cartItems.add(CartItem( name: name, count: count, price: price, imagePath: imagePath, )); } notifyListeners(); } void removeItem(CartItem item) { if (item.count > 1) { item.count -= 1; } else { cartItems.remove(item); } notifyListeners(); } void clearCart() { cartItems.clear(); notifyListeners(); } }
4. 修正购物车项数量显示
从Provider的购物车数据中获取对应商品的数量,确保显示正确:
Row( mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( onPressed: () { Provider.of<Count>(context, listen: false) .addItem( items[index].name, 1, items[index].price, items[index].imagePath, ); }, icon: const Icon(Icons.add), ), // 从Provider中读取对应商品的数量 Text( Provider.of<Count>(context) .cartItems .firstWhere( (cartItem) => cartItem.name == items[index].name, orElse: () => CartItem(name: '', count: 0, price: 0, imagePath: ''), ) .count .toString(), ), IconButton( onPressed: () { final targetItem = Provider.of<Count>(context, listen: false) .cartItems .firstWhere( (item) => item.name == items[index].name, orElse: () => CartItem(name: '', count: 0, price: 0, imagePath: ''), ); if (targetItem.name.isNotEmpty) { Provider.of<Count>(context, listen: false).removeItem(targetItem); } }, icon: const Icon(Icons.remove), ), ], ),
内容的提问来源于stack exchange,提问作者Salih
相关产品推荐
相关产品推荐

