Flutter计时器快速点击播放/暂停倒计时加速问题修复咨询
解决Flutter倒计时快速点击播放/暂停导致加速的问题
你的推测完全正确:快速点击按钮时,每次调用toggleTimer()都会创建新的Timer.periodic实例,多个定时器同时触发倒计时逻辑,导致时间减少速度翻倍。
修正方案
核心思路是持有单个定时器实例的引用,确保同一时间只有一个定时器在运行,每次启动新定时器前先取消已存在的实例:
- 在State类中添加
Timer?类型变量,用于保存当前定时器 - 重构
toggleTimer()方法,启动前先清理旧定时器 - 优化播放/暂停的状态逻辑,保持状态与定时器操作同步
- 在组件销毁时取消定时器,避免内存泄漏
修改后的完整代码
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:quickrest/styles/text_styles.dart'; import 'package:quickrest/styles/color_styles.dart'; import 'package:liquid_progress_indicator/liquid_progress_indicator.dart'; class ActiveTimerScreen extends StatefulWidget { const ActiveTimerScreen({super.key, required this.seconds}); final int seconds; @override State<ActiveTimerScreen> createState() => _ActiveTimerScreenState(); } class _ActiveTimerScreenState extends State<ActiveTimerScreen> { int _timeLeft = 0; bool timerStarted = false; // 新增:持有当前定时器引用 Timer? _timer; @override void initState() { super.initState(); _timeLeft = widget.seconds; timerStarted = true; toggleTimer(); } @override void dispose() { // 组件销毁时取消定时器 _timer?.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Material( child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox(width: double.infinity), Padding( padding: EdgeInsets.only( top: MediaQuery.of(context).size.height * 0.3, ), child: Text( '${_timeLeft ~/ 60} : ${(_timeLeft % 60).toString().padLeft(2, '0')}', style: activeTimerTitleTextStyle, ), ), Padding( padding: const EdgeInsets.only( top: 80.0, ), child: ElevatedButton( style: ElevatedButton.styleFrom( shape: const CircleBorder(), backgroundColor: Colors.black, ), onPressed: () { setState(() { timerStarted = !timerStarted; toggleTimer(); }); }, child: Padding( padding: const EdgeInsets.all(4.0), child: Icon( !timerStarted ? Icons.play_arrow : Icons.pause, size: 100, ), ), ), ), Padding( padding: const EdgeInsets.only(top: 80.0), child: OutlinedButton( onPressed: () { Navigator.of(context).pop(); }, style: OutlinedButton.styleFrom( backgroundColor: Colors.white, side: const BorderSide( color: Colors.white, ), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(24), ), ), ), child: const Text( "Cancel", style: activeTimerCancelTextStyle, ), ), ), ], ), ), ); } void toggleTimer() { const oneSec = Duration(seconds: 1); // 先取消已存在的定时器,避免多个实例同时运行 _timer?.cancel(); if (timerStarted && _timeLeft > 0) { _timer = Timer.periodic(oneSec, (Timer t) { setState(() { if (_timeLeft <= 1) { t.cancel(); timerStarted = false; _timeLeft = 0; } else { _timeLeft -= 1; } }); }); } } }
关键修改说明
- 新增
Timer? _timer变量,跟踪当前活跃的定时器实例 - 在
toggleTimer()开头先调用_timer?.cancel(),确保启动新定时器前旧的已经被销毁 - 重构按钮点击逻辑,直接切换
timerStarted状态后调用toggleTimer(),逻辑更简洁 - 在
dispose()中取消定时器,防止组件销毁后定时器仍在后台运行导致内存泄漏
内容的提问来源于stack exchange,提问作者Sachu
相关产品推荐
相关产品推荐

