Flutter弹窗倒计时异常及Navigator调试锁报错求助
问题分析与解决方案
问题根源
- 倒计时跳变:原代码中
StatefulBuilder的builder方法会在每次setState时重新执行,导致重复创建多个Timer.periodic,多个定时器同时修改倒计时秒数,造成跳变(如30→27→23)。 _debugLocked错误:在Timer回调中直接调用Navigator导航操作(pop和引导页next),此时Navigator可能处于状态锁定状态(如正在构建Widget),触发断言失败。
修复方案
将弹窗封装为独立的StatefulWidget,规范定时器生命周期,并延迟执行导航操作避开锁定:
1. 创建独立的倒计时弹窗Widget
class CountdownDialog extends StatefulWidget { final VoidCallback onCountdownFinish; const CountdownDialog({super.key, required this.onCountdownFinish}); @override State<CountdownDialog> createState() => _CountdownDialogState(); } class _CountdownDialogState extends State<CountdownDialog> { late int countdownSeconds; late Timer countdownTimer; @override void initState() { super.initState(); countdownSeconds = 30; // 仅在初始化时创建一次定时器,避免重复创建 countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { if (mounted) { setState(() { if (countdownSeconds > 0) { countdownSeconds--; } else { _finishCountdown(); } }); } else { timer.cancel(); } }); } void _finishCountdown() { countdownTimer.cancel(); // 延迟执行导航操作,避开Navigator锁定状态 WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.of(context).pop(); widget.onCountdownFinish(); }); } @override void dispose() { countdownTimer.cancel(); // 弹窗销毁时强制取消定时器,避免内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Alarm'), content: Column( mainAxisSize: MainAxisSize.min, children: [ Text('Let\'s start measuring. Automatically closes in ${countdownSeconds} seconds.'), const SizedBox(height: 16), Text('Time remaining: ${countdownSeconds} seconds'), ], ), actions: [ ElevatedButton( onPressed: () { countdownTimer.cancel(); Navigator.of(context).pop(); widget.onCountdownFinish(); }, child: const Text('close'), ), ], ); } }
2. 修改原弹窗调用方法
void _showCountdownDialog() { showDialog( context: context, barrierDismissible: false, builder: (context) { return CountdownDialog( onCountdownFinish: () { _introKey.currentState?.next(); // 倒计时结束/手动关闭后跳转引导页下一页 }, ); }, ); }
关键修复点说明
- 独立StatefulWidget:将弹窗逻辑封装后,
initState仅执行一次,确保定时器只创建一个,彻底解决倒计时跳变问题。 - 定时器生命周期管理:在
dispose方法和弹窗关闭时主动取消定时器,避免内存泄漏。 - 延迟导航操作:通过
WidgetsBinding.instance.addPostFrameCallback延迟执行导航操作,确保在当前Widget帧构建完成后再修改Navigator状态,避开锁定断言。
内容的提问来源于stack exchange,提问作者luds
相关产品推荐
相关产品推荐

