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

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: () {},
        ),
      ),
    );
  }
}

问题分析与修复方案

核心问题

  1. Counter类未持有orderUp的有效引用:代码中Counter直接使用orderUp,但该变量并非Counter的成员变量,导致Counter无法访问到正确的列表数据,循环无法执行,tempList始终为空,fold返回0。
  2. 全局tempList导致逻辑错误:tempList是全局变量,每次调用justdoit()都会追加元素,即使后续orderUp有数据,也会累加旧值,同时初始为空时直接返回0。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:07:05