Flutter使用Provider求和始终返回0的问题求助
问题:Provider计算总和始终返回0
我尝试通过继承ChangeNotifier的Counter类,结合for循环与fold方法实现数值求和并通过Provider返回结果:遍历orderUp列表,将其中每个元素的selectVar.amount值存入tempList,再通过fold方法计算tempList的总和并返回。但在DetailPage的Widget中通过context.watch<Counter>().justdoit().toString()展示结果时,始终显示0。
相关代码
Counter类
class Counter with ChangeNotifier { int justdoit() { for (var i = 0; i < orderUp.length; i++) { tempList.add(orderUp[i].selectVar.amount); } int count = tempList.fold(0, (previousValue, element) => previousValue + element); return count; } }
全局tempList
List<int> tempList = [];
展示结果的Widget
Container( padding: const EdgeInsets.all(15), decoration: const BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), child: Text( context.watch<Counter>().justdoit().toString(), style: const TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold, ), ), )
DetailPage完整代码
class DetailPage extends StatefulWidget { final Food food; DetailPage(this.food); @override State<DetailPage> createState() => _DetailPageState(); } class _DetailPageState extends State<DetailPage> { @override Widget build(BuildContext context) { context.watch<Counter>(); return Scaffold( appBar: AppBar( leadingWidth: 65, backgroundColor: Colors.transparent, leading: Padding( padding: const EdgeInsets.only(left: 24.0), child: Container( // ignore: prefer_const_constructors decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white, ), width: 40, height: 40, child: IconButton( icon: const Icon(Icons.arrow_back_ios_outlined), color: Colors.black, onPressed: () => Navigator.of(context).pop(), ), ), ), actions: [ Padding( padding: const EdgeInsets.only(right: 24.0), child: Container( // ignore: prefer_const_constructors decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white, ), width: 40, height: 40, child: IconButton( icon: Icon( ((context.read<FavFood>().favorited(widget.food) == false) ? Icons.favorite_outline : Icons.favorite), color: Colors.black, ), onPressed: () { bool click2 = context.read<FavFood>().favorited(widget.food); (context.read<FavFood>().rev(widget.food)); (context.read<FavFood>().favorited(widget.food)); setState(() { click2 = !click2; }); context.read<FavFood>().favorited(widget.food); }, ), ), ), ], ), backgroundColor: Color(0xff453658), body: SingleChildScrollView( child: Column( children: [ FoodImg(widget.food), FoodDetail(widget.food), ], ), ), floatingActionButton: SizedBox( width: 100, height: 56, child: RawMaterialButton( fillColor: const Color(0xff453658), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(50), ), elevation: 2, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ IconButton( icon: const Icon(Icons.shopping_cart_outlined), color: Colors.black, onPressed: () { Navigator.of(context).pushNamed(cartRoute); context.read<TotalPrice>().update(); }, ), Container( padding: const EdgeInsets.all(15), decoration: const BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), child: Text( context.watch<Counter>().justdoit().toString(), style: const TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold, ), ), ), ], ), onPressed: () {}, ), ), ); } }
问题分析与修复方案
核心问题
- Counter类未持有orderUp的有效引用:代码中Counter直接使用
orderUp,但该变量并非Counter的成员变量,导致Counter无法访问到正确的列表数据,循环无法执行,tempList始终为空,fold返回0。 - 全局tempList导致逻辑错误:tempList是全局变量,每次调用
justdoit()都会追加元素,即使后续orderUp有数据,也会累加旧值,同时初始为空时直接返回0。 - Provider使用逻辑错误:在build方法中直接调用
justdoit(),既没有监听orderUp的变化,也没有让Counter在数据更新时通知UI刷新。
修复后的代码
重构Counter类
class Counter with ChangeNotifier { // 持有orderUp的成员变量,确保能访问到正确数据 List<OrderItem> _orderUp = []; Counter(List<OrderItem> initialOrder) : _orderUp = initialOrder; // 直接计算总和,无需临时列表,避免数据污染 int calculateTotalAmount() { return _orderUp.fold(0, (sum, item) => sum + item.selectVar.amount); } // 当orderUp数据变化时,更新内部列表并通知UI刷新 void updateOrderList(List<OrderItem> newOrder) { _orderUp = newOrder; notifyListeners(); } }
修改Provider初始化
在父Widget或应用入口初始化Counter时,传入正确的orderUp实例:
ChangeNotifierProvider( create: (context) => Counter(yourOrderUpList), // 传入实际的orderUp列表 child: DetailPage(food), )
更新DetailPage中的使用方式
Container( padding: const EdgeInsets.all(15), decoration: const BoxDecoration( color: Colors.white, shape: BoxShape.circle, ), child: Text( context.watch<Counter>().calculateTotalAmount().toString(), style: const TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold, ), ), )
额外说明
- 如果orderUp是在其他Provider中维护的(比如CartProvider),可以直接在该Provider中实现计算总和的方法,避免冗余的Counter类。
- 每次orderUp数据变更时,需要调用Counter的
updateOrderList()方法,确保UI能收到更新通知,实时展示最新的总和。
内容的提问来源于stack exchange,提问作者shimomaru
相关产品推荐
相关产品推荐

