Flutter+SQFLite:无状态Widget中按日期增改饮水数据的问题
解决SQFLite饮水记录数据库的三个核心问题
问题1:无法正确判断当日数据是否存在,仅能插入无法更新
原因:
- 异步查询未加
await,判断逻辑执行时还未拿到数据库数据,导致筛选结果始终为空 - 判断逻辑完全反转:存在当日数据时应执行更新,却触发了插入操作
- 查询方法未传入当日日期,无法精准筛选目标记录
解决方法:
- 将
WaterButtonsGrouped改为StatefulWidget,持久保存累计饮水量状态 - 异步操作必须加
await,确保拿到数据库结果后再执行判断 - 修正逻辑:当日有数据则更新,无数据则插入
- 给数据库查询方法传入当日日期,精准定位目标记录
问题2:进度指示器无法同步正确饮水数据
原因:
- 主页面每次调用
WaterButtonsGrouped().addWater()都会创建新实例,拿到的是初始值而非实时累计值 - 进度指示器仅在初始化时计算一次百分比,后续数据变更无法触发重绘
- 组件间无状态同步机制,数据更新无法通知到指示器
解决方法:
- 使用
GlobalKey获取WaterButtonsGrouped的实例,直接读取实时累计值 - 给
WaterButtonsGrouped添加回调函数,按钮点击后通知主页面更新数据 - 重写进度指示器的
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
相关产品推荐
相关产品推荐

