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

Flutter调用Provider方法传参报错 卡路里计算结果无法正常显示

问题根因

报错和功能异常来自3个核心问题:

  • 页面初始构建时TextEditingController的text为空字符串,直接传给DateFormat.parse()会触发格式解析报错,对应Trying to read d from at position 0错误;传入controller.toString()时,传递的是控制器实例的字符串描述,并非用户输入的日期文本,同样会解析失败。
  • getTotal方法逻辑错误:筛选出指定日期的卡路里列表date后,求和时遍历的是全量myCalories列表,最终计算的是所有记录的总卡路里,而非指定日期的数值。
  • 在StatelessWidget中创建TextEditingController未做生命周期管理,且点击搜索后未触发页面刷新,即使计算出结果也不会更新到UI上。
修复方案

1. 调整Provider层代码

给AllCalories增加存储查询结果的变量,修正求和逻辑,增加空值与格式校验:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:my_plate/models/calories.dart';

class AllCalories with ChangeNotifier {
  List<Calories> myCalories = [];
  // 存储查询到的当日总卡路里,null代表未查询或无有效结果
  double? dailyTotal;

  List<Calories> getMyCalories() {
    return myCalories;
  }

  void getTotal(String inputDate) {
    // 空输入直接重置结果
    if(inputDate.trim().isEmpty) {
      dailyTotal = null;
      notifyListeners();
      return;
    }
    try {
      var dateTime = DateFormat('d/M/y').parse(inputDate);
      var tmrDate = dateTime.add(const Duration(days: 1));

      // 筛选指定日期的记录
      List<Calories> dateList = myCalories.where((o) {
        return o.consumptionDate.isAfter(dateTime) &&
            o.consumptionDate.isBefore(tmrDate);
      }).toList();
      
      double sum = 0;
      // 仅对筛选后的当日记录求和
      for (var item in dateList) {
        sum += item.numCalories;
      }
      dailyTotal = sum;
    } catch(e) {
      // 日期格式错误时重置结果,避免崩溃
      dailyTotal = null;
    }
    // 通知监听的UI刷新数据
    notifyListeners();
  }
}

2. 调整RecordsPage页面代码

将StatelessWidget改为StatefulWidget管理控制器生命周期,移除build阶段直接调用getTotal的逻辑,根据查询状态动态展示结果:

import 'package:flutter/material.dart';
import 'package:my_plate/models/calories.dart';
import 'package:my_plate/providers/all_calories.dart';
import 'package:my_plate/screens/home_screen.dart';
import 'package:my_plate/screens/login_screen.dart';
import 'package:my_plate/widgets/app_drawer.dart';
import 'package:provider/provider.dart';

class RecordsPage extends StatefulWidget {
  static String routeName = '/records';

  @override
  State<RecordsPage> createState() => _RecordsPageState();
}

class _RecordsPageState extends State<RecordsPage> {
  final controller = TextEditingController();

  @override
  void dispose() {
    // 页面销毁时释放控制器,避免内存泄漏
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    AllCalories myCalories = Provider.of<AllCalories>(context);
    return Scaffold(
        resizeToAvoidBottomInset: true,
        backgroundColor: Colors.white,
        appBar: AppBar(
          title: Text('Previous Records'),
          elevation: 0,
          brightness: Brightness.light,
          backgroundColor: Color(0xff588157),
          leading: IconButton(
            onPressed: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => MainScreen(),
                  ));
            },
            icon: Icon(
              Icons.arrow_back,
              size: 20,
              color: Colors.white,
            ),
          ),
        ),
        body: SingleChildScrollView(
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 40),
            child: Column(children: [
              Image.asset('images/date.png', alignment: Alignment.topCenter),
              TextField(
                controller: controller,
                decoration: InputDecoration(
                    enabledBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: Color(0xff588157)),
                    ),
                    focusedBorder: UnderlineInputBorder(
                      borderSide: BorderSide(color: Color(0xff588157)),
                    ),
                    hintText: '请输入d/M/y格式日期,例如1/10/2024',
                    suffixIcon: IconButton(
                        onPressed: () {
                          // 点击搜索时才触发计算
                          myCalories.getTotal(controller.text);
                          // 自动收起键盘
                          FocusScope.of(context).unfocus();
                        },
                        icon: Icon(Icons.search))),
              ),
              SizedBox(height: 20),
              Row(
                children: [
                  Text(
                    myCalories.dailyTotal == null 
                    ? '请输入日期后点击搜索查询'
                    : '当日总摄入卡路里:${myCalories.dailyTotal!.toStringAsFixed(0)}',
                    textAlign: TextAlign.center,
                    style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
                  ),
                ],
              ),
            ]),
          ),
        ),
        drawer: AppDrawer());
  }
}
关键修改说明
  • 初始页面构建阶段不触发日期解析,从根源避免空字符串解析报错
  • 仅在用户点击搜索按钮时执行计算逻辑,计算完成通过notifyListeners()触发UI刷新
  • 修正求和逻辑,仅遍历筛选后的当日记录,保证计算结果准确
  • 增加异常捕获,用户输入格式错误时不会触发崩溃
  • 控制器随页面生命周期销毁,避免内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:54:23