Flutter中从Cart Bloc获取商品ID并合并数量生成指定结构
问题需求
需要从Cart Bloc的商品列表中提取productID,并与购物车数量合并,生成如下格式的JSON结构:
"aos": [ { "product_id": 10, "quantity": 1 }, { "product_id": 11, "quantity": 2 } ]
此前尝试将Map编码为JSON,但无法访问每个商品的id,需在Bloc架构下实现该需求。
相关代码
Checkout Screen代码
class CheckoutScreen extends StatelessWidget { @override Widget build(BuildContext context) { // final List<dynamic> aos; return Scaffold( appBar: AppBar( backgroundColor: buttonBG, ), body: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ const ShippingAddress(), const SizedBox(height: 20), BlocBuilder<CartBloc, CartState>( builder: (context, state) { if (state is CartLoaded) { Map aos = state.cart.productQuantity(state.cart.products); var pio = aos.keys.toList(); String productInstance = json.encode(pio); debugPrint(productInstance); return Expanded( child: SizedBox( height: 400, child: ListView.builder( itemCount: aos.keys.length, itemBuilder: (BuildContext context, int index) { final pIndex = aos.keys.elementAt(index); final qIndex = aos.values.elementAt(index); return ProductCard.summary( product: pIndex, quantity: qIndex, ); }, ), ), ); } return const Text('Something went wrong'); }, ), ], )); } }
CartModel代码
import 'package:afia4_shopping_app/logic/models/product_models.dart'; import 'package:equatable/equatable.dart'; class Cart extends Equatable { final List<ProductModel> products; const Cart({this.products = const <ProductModel>[]}); @override List<Object?> get props => [products]; Map productQuantity(products) { var quantity = {}; products.forEach((product) { if (!quantity.containsKey(product)) { quantity[product] = 1; } else { quantity[product] += 1; } }); return quantity; } }
CartBloc代码
class CartBloc extends Bloc<CartEvent, CartState> { CartBloc() : super(CartLoading()) { on<LoadCart>(_onLoadCart); on<AddProduct>(_onAddProduct); on<RemoveProduct>(_onRemoveProduct); } void _onLoadCart( LoadCart event, Emitter<CartState> emit, ) async { emit(CartLoading()); try { await Future<void>.delayed(const Duration(seconds: 1)); emit(CartLoaded()); } catch (_) { emit(CartError()); } } void _onAddProduct( AddProduct event, Emitter<CartState> emit, ) { if (state is CartLoaded) { try { emit( CartLoaded( cart: Cart( products: List.from((state as CartLoaded).cart.products) ..add(event.product), ), ), ); } on Exception { emit(CartError()); } } } void _onRemoveProduct( RemoveProduct event, Emitter<CartState> emit, ) { if (state is CartLoaded) { try { emit( CartLoaded( cart: Cart( products: List.from((state as CartLoaded).cart.products) ..remove(event.product), ), ), ); } on Exception { emit(CartError()); } } } }
ProductModel代码
class ProductModel { ProductModel( {this.name, this.id, }); String? name; int? id; factory ProductModel.fromJson(Map<String, dynamic> json) => ProductModel( name: json["name"], id: json["id"], Map<String, dynamic> toJson() => { "name": name, "id": id }; List<ProductModel> productsFromJson(String str) => List<ProductModel>.from( json.decode(str).map((x) => ProductModel.fromJson(x))); String productsToJson(List<ProductModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson()))); }
解决方案
1. 修复CartModel的数量统计逻辑
原productQuantity方法用ProductModel对象作为Map的key,这会导致无法直接提取商品id,且对象比较可能出现异常。修改为用商品id作为key来统计数量:
// 修改Cart类中的productQuantity方法 Map<int, int> productQuantity() { final quantity = <int, int>{}; for (final product in products) { if (product.id == null) continue; // 处理id为空的情况 final productId = product.id!; quantity[productId] = (quantity[productId] ?? 0) + 1; } return quantity; }
这里指定了Map的泛型<int, int>,让类型更安全,同时直接使用当前Cart类的products属性,不需要再传参。
2. 在CheckoutScreen中生成目标结构
在BlocBuilder中,通过修改后的productQuantity获取id和数量的映射,再转换成目标格式的列表,最后编码为JSON:
BlocBuilder<CartBloc, CartState>( builder: (context, state) { if (state is CartLoaded) { // 获取id-数量的映射 final quantityMap = state.cart.productQuantity(); // 生成目标aos列表 final aos = quantityMap.entries.map((entry) { return { "product_id": entry.key, "quantity": entry.value, }; }).toList(); // 编码为JSON字符串 final aosJson = json.encode({"aos": aos}); debugPrint(aosJson); // 打印验证结构 return Expanded( child: SizedBox( height: 400, child: ListView.builder( itemCount: quantityMap.length, itemBuilder: (BuildContext context, int index) { final entry = quantityMap.entries.elementAt(index); // 根据id找到对应的商品(如果需要展示商品信息) final product = state.cart.products.firstWhere( (p) => p.id == entry.key, orElse: () => ProductModel(), ); return ProductCard.summary( product: product, quantity: entry.value, ); }, ), ), ); } return const Text('Something went wrong'); }, )
3. 修复CartBloc的初始加载逻辑
原_onLoadCart方法中emit(CartLoaded())没有传递cart参数,会导致空指针问题,修改为传递默认空购物车:
void _onLoadCart( LoadCart event, Emitter<CartState> emit, ) async { emit(CartLoading()); try { await Future<void>.delayed(const Duration(seconds: 1)); emit(const CartLoaded(cart: Cart())); // 传递默认空Cart } catch (_) { emit(CartError()); } }
通过以上修改,就能正确生成你需要的JSON结构,同时解决无法访问商品id的问题。
内容的提问来源于stack exchange,提问作者pythonGo
相关产品推荐
相关产品推荐

