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

Flutter电商APP购物车会话管理问题(基于SharedPreference)

基于SharedPreference的Flutter购物车持久化解决方案

1. 定义可序列化的购物车商品模型

SharedPreference仅支持存储基础类型,因此需要将商品数据序列化为JSON字符串。创建CartItem类并实现序列化/反序列化方法:

class CartItem {
  final String id;
  final String name;
  final double price;
  final int quantity;

  CartItem({
    required this.id,
    required this.name,
    required this.price,
    required this.quantity,
  });

  // 转JSON对象
  Map<String, dynamic> toJson() => {
        'id': id,
        'name': name,
        'price': price,
        'quantity': quantity,
      };

  // 从JSON转对象
  factory CartItem.fromJson(Map<String, dynamic> json) => CartItem(
        id: json['id'],
        name: json['name'],
        price: json['price'],
        quantity: json['quantity'],
      );
}

2. 创建全局购物车管理单例

用单例类统一处理购物车的增删改查及SharedPreference读写,确保全项目数据同步:

import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';

class CartManager {
  static final CartManager _instance = CartManager._internal();
  factory CartManager() => _instance;
  CartManager._internal();

  List<CartItem> _cartItems = [];
  final String _storageKey = 'app_cart_items';

  // 初始化:从SharedPreference加载历史数据
  Future<void> init() async {
    final prefs = await SharedPreferences.getInstance();
    final String? cartJson = prefs.getString(_storageKey);
    if (cartJson != null) {
      List<dynamic> jsonList = jsonDecode(cartJson);
      _cartItems = jsonList.map((item) => CartItem.fromJson(item)).toList();
    }
  }

  // 获取只读购物车列表
  List<CartItem> get cartItems => List.unmodifiable(_cartItems);

  // 添加商品(已存在则累加数量)
  Future<void> addItem(CartItem item) async {
    final existingIndex = _cartItems.indexWhere((cartItem) => cartItem.id == item.id);
    if (existingIndex != -1) {
      _cartItems[existingIndex] = CartItem(
        id: item.id,
        name: item.name,
        price: item.price,
        quantity: _cartItems[existingIndex].quantity + item.quantity,
      );
    } else {
      _cartItems.add(item);
    }
    await _saveToStorage();
  }

  // 更新商品数量(数量≤0则删除)
  Future<void> updateQuantity(String itemId, int newQuantity) async {
    final index = _cartItems.indexWhere((item) => item.id == itemId);
    if (index != -1 && newQuantity > 0) {
      _cartItems[index] = CartItem(
        id: _cartItems[index].id,
        name: _cartItems[index].name,
        price: _cartItems[index].price,
        quantity: newQuantity,
      );
      await _saveToStorage();
    } else if (newQuantity <= 0) {
      await removeItem(itemId);
    }
  }

  // 删除商品
  Future<void> removeItem(String itemId) async {
    _cartItems.removeWhere((item) => item.id == itemId);
    await _saveToStorage();
  }

  // 清空购物车
  Future<void> clearCart() async {
    _cartItems.clear();
    await _saveToStorage();
  }

  // 私有方法:将购物车数据持久化到SharedPreference
  Future<void> _saveToStorage() async {
    final prefs = await SharedPreferences.getInstance();
    List<Map<String, dynamic>> jsonList = _cartItems.map((item) => item.toJson()).toList();
    await prefs.setString(_storageKey, jsonEncode(jsonList));
  }
}

3. 启动APP时初始化购物车

在main函数中提前加载历史购物车数据,确保APP启动后数据可用:

import 'package:flutter/material.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await CartManager().init();
  runApp(const MyApp());
}

4. 各页面集成购物车功能

商品页添加商品

// 商品页添加按钮点击事件
onPressed: () async {
  final newCartItem = CartItem(
    id: 'prod_001',
    name: '示例商品',
    price: 99.9,
    quantity: 1,
  );
  await CartManager().addItem(newCartItem);
  // 可添加弹窗提示或直接跳转购物车页
},

购物车页展示商品

结合ChangeNotifier实现数据实时刷新(需修改CartManager继承ChangeNotifier,并在数据变更时调用notifyListeners()):

// 修改CartManager继承ChangeNotifier
class CartManager extends ChangeNotifier {
  // ... 原有代码 ...
  Future<void> addItem(CartItem item) async {
    // ... 原有逻辑 ...
    await _saveToStorage();
    notifyListeners(); // 通知页面刷新
  }
  // updateQuantity、removeItem、clearCart方法均需添加notifyListeners()
}

// 购物车页面代码
class CartPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('购物车')),
      body: Consumer<CartManager>(
        builder: (context, cartManager, child) {
          if (cartManager.cartItems.isEmpty) {
            return const Center(child: Text('购物车为空'));
          }
          return ListView.builder(
            itemCount: cartManager.cartItems.length,
            itemBuilder: (context, index) {
              final item = cartManager.cartItems[index];
              return ListTile(
                title: Text(item.name),
                subtitle: Text('¥${item.price} x ${item.quantity}'),
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    IconButton(
                      icon: const Icon(Icons.remove),
                      onPressed: () => cartManager.updateQuantity(item.id, item.quantity - 1),
                    ),
                    Text('${item.quantity}'),
                    IconButton(
                      icon: const Icon(Icons.add),
                      onPressed: () => cartManager.updateQuantity(item.id, item.quantity + 1),
                    ),
                  ],
                ),
              );
            },
          );
        },
      ),
    );
  }
}

首页展示购物车入口及数量

在首页AppBar添加购物车图标,并实时显示商品数量:

AppBar(
  title: const Text('首页'),
  actions: [
    Stack(
      children: [
        IconButton(
          icon: const Icon(Icons.shopping_cart),
          onPressed: () {
            Navigator.push(context, MaterialPageRoute(builder: (_) => CartPage()));
          },
        ),
        Positioned(
          right: 8,
          top: 8,
          child: Container(
            padding: const EdgeInsets.all(2),
            decoration: BoxDecoration(
              color: Colors.red,
              borderRadius: BorderRadius.circular(10),
            ),
            constraints: const BoxConstraints(minWidth: 16, minHeight: 16),
            child: Consumer<CartManager>(
              builder: (context, cartManager, child) {
                return Text(
                  '${cartManager.cartItems.length}',
                  style: const TextStyle(color: Colors.white, fontSize: 12),
                  textAlign: TextAlign.center,
                );
              },
            ),
          ),
        ),
      ],
    ),
  ],
)

核心优势

  • 单例模式确保全项目使用同一购物车数据源,避免页面跳转数据不一致
  • SharedPreference持久化存储,APP重启后购物车数据不会丢失
  • 结合ChangeNotifier实现页面数据实时刷新,无需手动重载页面

内容的提问来源于stack exchange,提问作者Dhaneshwar Shruti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:41:16