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

Flutter+SQFLite:无状态Widget中按日期增改饮水数据的问题

解决SQFLite饮水记录数据库的三个核心问题

问题1:无法正确判断当日数据是否存在,仅能插入无法更新

原因:

  • 异步查询未加await,判断逻辑执行时还未拿到数据库数据,导致筛选结果始终为空
  • 判断逻辑完全反转:存在当日数据时应执行更新,却触发了插入操作
  • 查询方法未传入当日日期,无法精准筛选目标记录

解决方法:

  1. 将WaterButtonsGrouped改为StatefulWidget,持久保存累计饮水量状态
  2. 异步操作必须加await,确保拿到数据库结果后再执行判断
  3. 修正逻辑:当日有数据则更新,无数据则插入
  4. 给数据库查询方法传入当日日期,精准定位目标记录

问题2:进度指示器无法同步正确饮水数据

原因:

  • 主页面每次调用WaterButtonsGrouped().addWater()都会创建新实例,拿到的是初始值而非实时累计值
  • 进度指示器仅在初始化时计算一次百分比,后续数据变更无法触发重绘
  • 组件间无状态同步机制,数据更新无法通知到指示器

解决方法:

  1. 使用GlobalKey获取WaterButtonsGrouped的实例,直接读取实时累计值
  2. 给WaterButtonsGrouped添加回调函数,按钮点击后通知主页面更新数据
  3. 重写进度指示器的didUpdateWidget方法,接收新数据时自动更新百分比

问题3:无Builder场景下的数据筛选

原因:原有查询方法未接收日期参数,无法针对当日数据做精准筛选

解决方法:
在DBHelper中新增按日期查询的方法,传入当日日期即可获取对应记录,无需依赖Builder组件


修改后的完整代码

1. WaterButtonsGrouped(改为StatefulWidget)

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'water_db_helper.dart';
import 'water_button_model.dart';

class WaterButtonsGrouped extends StatefulWidget {
  final VoidCallback? onWaterUpdated;

  const WaterButtonsGrouped({super.key, this.onWaterUpdated});

  @override
  State<WaterButtonsGrouped> createState() => _WaterButtonsGroupedState();
}

class _WaterButtonsGroupedState extends State<WaterButtonsGrouped> {
  int totalWaterDrank = 0;
  final String todayDate = DateFormat.yMMMd().format(DateTime.now());

  // 查询当日饮水记录
  Future<List<Map<String, dynamic>>> _getTodayWaterRecord() async {
    return await WaterDBHelper.getWaterByDate(todayDate);
  }

  // 处理按钮点击,累加并同步数据库
  Future<void> addInput(WaterButtonModel model) async {
    setState(() {
      totalWaterDrank += model.waterMillimeters;
    });

    final todayRecords = await _getTodayWaterRecord();
    if (todayRecords.isEmpty) {
      await WaterDBHelper.insertWater(todayDate, totalWaterDrank);
      print('插入当日数据:$totalWaterDrank ml');
    } else {
      final recordId = todayRecords[0]['id'];
      await WaterDBHelper.updateWaterDrank(recordId, totalWaterDrank);
      print('更新当日数据:$totalWaterDrank ml');
    }

    // 通知主页面更新指示器
    widget.onWaterUpdated?.call();
  }

  // 对外暴露当前累计饮水量
  int getCurrentTotal() {
    return totalWaterDrank;
  }

  // 初始化时加载当日已有数据
  @override
  void initState() {
    super.initState();
    _loadTodayData();
  }

  Future<void> _loadTodayData() async {
    final todayRecords = await _getTodayWaterRecord();
    if (todayRecords.isNotEmpty) {
      setState(() {
        totalWaterDrank = todayRecords[0]['waterMillimeters'] as int;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Wrap(
      children: [
        WaterButton(
          buttonModel: WaterButtonModel.cup(),
          onPressed: addInput,
        ),
        WaterButton(
          buttonModel: WaterButtonModel.glass(),
          onPressed: addInput,
        ),
        WaterButton(
          buttonModel: WaterButtonModel.bottle(),
          onPressed: addInput,
        ),
        WaterButton(
          buttonModel: WaterButtonModel.canister(),
          onPressed: addInput,
        ),
      ],
    );
  }
}

2. 主页面(添加状态同步)

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'water_buttons_grouped.dart';
import 'water_progress_indicator.dart';

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey<_WaterButtonsGroupedState> _waterButtonsKey = GlobalKey();
  int currentWaterDrank = 0;

  // 更新饮水量并刷新UI
  void _updateWaterDrank() {
    setState(() {
      currentWaterDrank = _waterButtonsKey.currentState?.getCurrentTotal() ?? 0;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        resizeToAvoidBottomInset: false,
        body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const SizedBox(height: 15),
            Align(
              alignment: Alignment.center,
              child: Text(
                "Hydration Level",
                style: GoogleFonts.comfortaa(fontSize: 50),
              ),
            ),
            const SizedBox(height: 50),
            Container(
              width: 300,
              height: 300,
              child: WaterProgressIndicator(waterDrank: currentWaterDrank),
            ),
            const SizedBox(height: 50),
            WaterButtonsGrouped(
              key: _waterButtonsKey,
              onWaterUpdated: _updateWaterDrank,
            ),
          ],
        ),
      ),
    );
  }
}

3. WaterProgressIndicator(支持动态更新)

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:liquid_progress_indicator_v2/liquid_progress_indicator.dart';

class WaterProgressIndicator extends StatefulWidget {
  final int waterDrank;

  const WaterProgressIndicator({super.key, required this.waterDrank});

  @override
  State<WaterProgressIndicator> createState() => _WaterProgressIndicatorState();
}

class _WaterProgressIndicatorState extends State<WaterProgressIndicator> {
  static const int waterGoal = 2000;
  late double percentage;

  @override
  void initState() {
    super.initState();
    percentage = _calculatePercentage();
  }

  @override
  void didUpdateWidget(covariant WaterProgressIndicator oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.waterDrank != widget.waterDrank) {
      setState(() {
        percentage = _calculatePercentage();
      });
    }
  }

  double _calculatePercentage() {
    return widget.waterDrank / waterGoal;
  }

  @override
  Widget build(BuildContext context) {
    return LiquidCircularProgressIndicator(
      value: percentage,
      borderColor: Colors.blue.shade800,
      borderWidth: 7.0,
      direction: Axis.vertical,
      center: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(
            '${(percentage * 100).round()} %',
            style: GoogleFonts.deliciousHandrawn(
              color: Colors.blue.shade700,
              fontSize: 100,
            ),
          ),
          const Text(
            'DRANK',
            style: TextStyle(
              color: Colors.black,
              fontSize: 25,
            ),
          ),
          const Text(
            'TOTAL',
            style: TextStyle(
              color: Colors.grey,
              fontSize: 20,
            ),
          ),
        ],
      ),
    );
  }
}

4. DBHelper新增按日期查询方法

// 在WaterDBHelper类中添加
static Future<List<Map<String, dynamic>>> getWaterByDate(String date) async {
  final db = await database;
  return db.query(
    'water',
    where: 'date = ?',
    whereArgs: [date],
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 17:57:02