Flutter周期性定时器重启后加速问题求助
定时器连续点击后加速异常的解决方法
问题现象
使用周期性Timer实现倒计时逻辑,启动时初始化定时器。但连续点击InkWell组件后,等待2秒重启定时器,会出现定时器加速运行的异常情况。
问题原因
- 旧定时器未彻底取消:连续快速点击InkWell时,多个异步延迟任务会在2秒后先后调用
startTimer(),每次调用都会创建新的Timer实例,旧Timer可能未被正确取消,导致多个Timer同时执行,造成加速效果。 - 异步延迟期间并发冲突:连续点击会触发多个
onTap回调,每个回调都会发起2秒延迟,延迟结束后都会执行startTimer(),导致Timer被重复创建。
修复方案
- 点击时立即取消当前定时器,无需嵌套在
setState中(取消操作不涉及UI状态更新)。 - 添加状态标记,防止延迟期间重复触发定时器重启逻辑。
- 在启动新定时器前强制取消旧实例,确保全局只有一个Timer在运行。
修复后的完整代码
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:wordgame/controller.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp(title: 'Material App', home: MyWidget()); } } class MyWidget extends StatefulWidget { const MyWidget({super.key}); @override State<MyWidget> createState() => _MyWidgetState(); } class _MyWidgetState extends State<MyWidget> { @override void initState() { startTimer(); super.initState(); } late Duration duration; Timer? timer; bool _isRestarting = false; // 标记是否处于定时器重启流程中 void startTimer() { // 启动新定时器前先取消旧实例,确保唯一性 cancelTimer(); duration = const Duration(seconds: 5); myController.selectMainWord(); myController.selectValueWords(); myController.selectedIndex = -1; timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (duration.inSeconds > 0) { duration -= const Duration(seconds: 1); print(duration.inSeconds.toString()); } else { duration = const Duration(seconds: 5); } setState(() {}); }); } void cancelTimer() { timer?.cancel(); timer = null; } MyController myController = MyController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Column( children: [ Container( child: Text( myController.mainWord, style: const TextStyle(fontSize: 36), ), ), Expanded( child: GridView.builder( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200, childAspectRatio: 3 / 2, crossAxisSpacing: 20, mainAxisSpacing: 20), itemCount: myController.valueWordList.length, itemBuilder: (BuildContext context, int index) { return InkWell( onTap: () async { // 处于重启流程时直接返回,避免重复触发 if (_isRestarting) return; myController.selectedIndex = index; setState(() {}); // 立即取消当前定时器 cancelTimer(); _isRestarting = true; await Future.delayed(const Duration(seconds: 2)); startTimer(); _isRestarting = false; }, child: Container( color: myController.isRightWord(index) && myController.selectedIndex == index ? Colors.green : Colors.blue, alignment: Alignment.center, child: Text( myController.valueWordList[index], style: const TextStyle(fontSize: 36), ), ), ); }, ), ), Container( child: Text(duration.inSeconds.toString()), ) ], ), ); } @override void dispose() { // 页面销毁时取消定时器,避免内存泄漏 cancelTimer(); super.dispose(); } }
关键修复点
- 新增
_isRestarting布尔标记,拦截延迟期间的重复点击请求。 - 在
startTimer开头强制调用cancelTimer(),确保每次启动新定时器前旧实例已被销毁。 - 将取消定时器的操作从
setState中移出,简化逻辑并保证执行时机。 - 重写
dispose方法,在页面销毁时清理定时器,避免内存泄漏。
内容的提问来源于stack exchange,提问作者hasannn2666
相关产品推荐
相关产品推荐

