You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中SharedPreferences结合Provider加载购物车数据失败问题

问题分析
  1. Provider实例不匹配:加载时新建的Count countObject和Provider注入到应用中的实例不是同一个,导致加载的数据无法同步到购物车状态。
  2. 数据保存格式错误:保存时把所有购物车项合并成单个字符串后添加到列表,加载时却按单个购物车项解析,导致数据分割错乱。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:34:56