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

Flutter Web页面刷新后,如何终止残留的Timer.periodic定时器?

Flutter Web页面刷新后定时器重复触发的解决方法

在Flutter Web中使用Timer.periodic实现的时钟组件,页面刷新(F5/Ctrl+F5)后出现多个定时器同时触发的问题——原因是旧页面实例的定时器未被正确销毁,新页面又创建了新的定时器,导致重复执行。

核心思路

通过全局追踪定时器 + 监听浏览器页面卸载事件,确保页面刷新/关闭时彻底清理所有活跃的定时器,避免旧实例的定时器继续运行。

具体实现步骤

  1. 全局管理定时器实例
    创建静态列表保存所有活跃的Timer实例,方便统一管理和清理。

  2. 监听浏览器beforeunload事件
    在Web环境下,通过dart:js库注册页面卸载前的事件,触发时取消所有全局追踪的定时器。

  3. 优化组件内的定时器逻辑
    在组件的initState和dispose中,将定时器加入/移出全局列表,并确保每次创建新定时器前先取消旧的。

修改后的代码示例

1. 全局定时器管理工具类

import 'dart:async';
import 'dart:js' as js;

class TimerManager {
  static final List<Timer> _timers = [];

  // 添加定时器并监听页面卸载事件
  static void addTimer(Timer timer) {
    _timers.add(timer);
    // 仅注册一次beforeunload事件
    if (_timers.length == 1) {
      js.context['onbeforeunload'] = () {
        cancelAllTimers();
      };
    }
  }

  // 移除并取消单个定时器
  static void removeTimer(Timer timer) {
    if (_timers.contains(timer)) {
      timer.cancel();
      _timers.remove(timer);
    }
  }

  // 取消所有定时器
  static void cancelAllTimers() {
    for (var timer in _timers) {
      timer.cancel();
    }
    _timers.clear();
  }
}

2. 修改后的WatchText组件

import 'dart:async';
import 'package:flutter/material.dart';

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

  @override
  State<WatchText> createState() => _WatchTextState();
}

class _WatchTextState extends State<WatchText> {
  late String _timeString;
  Timer? timer;

  @override
  void dispose() {
    if (timer != null) {
      TimerManager.removeTimer(timer!);
    }
    super.dispose();
  }

  @override
  void initState() {
    super.initState();
    // 格式化当前时间为时分秒
    _timeString = DateTime.now().toIso8601String().substring(11, 19);
    
    // 清理旧定时器(如果存在)
    if (timer != null) {
      TimerManager.removeTimer(timer!);
    }
    
    // 创建新定时器并加入全局管理
    timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _timeString = DateTime.now().toIso8601String().substring(11, 19);
      });
      print("timer update : $_timeString");
    });
    TimerManager.addTimer(timer!);
  }

  @override
  Widget build(BuildContext context) {
    return Text(_timeString, style: const TextStyle(fontSize: 24));
  }
}

原理说明

  • 全局列表:确保所有创建的定时器都被追踪,即使组件的dispose未被触发(比如页面刷新时),也能通过全局方法清理。
  • beforeunload事件:浏览器在页面刷新、关闭前会触发该事件,此时调用cancelAllTimers()可以彻底终止所有旧的定时器,避免它们在后台继续运行。

内容的提问来源于stack exchange,提问作者Roar Grønmo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 14:42:48