Flutter开发中Timer.periodic定时器无法停止该怎么解决?
Flutter 轮询拉取消息Timer无法停止的解决方案
问题核心原因
你遇到的Timer停不掉本质是存在多个未被持有引用的Timer实例同时运行:
- build方法会因为状态更新、父组件重绘等场景多次触发,只要触发时消息列表为空,就会创建新的Timer实例
- 你定义的
timer变量仅能存储最后一次创建的Timer引用,之前创建的Timer没有被你持有,自然无法调用cancel()销毁,会一直执行回调输出日志
修复方案
1. 每次创建Timer前先清空旧实例
修改启动逻辑,不管当前是否需要创建新Timer,先把已有的Timer销毁,避免多实例残留:
void onBuild() { // 先销毁已存在的Timer,避免多实例 if (timer != null) { timer!.cancel(); timer = null; } if (state.messages.isEmpty) { _checkEmptyMessages(); timer = Timer.periodic( const Duration(seconds: 5), (Timer t) => _checkEmptyMessages()); } }
2. (推荐)将Timer启停逻辑移到Bloc状态监听中
build方法触发频率不可控,更稳妥的方式是在State初始化时监听Bloc的状态变化,按需启停Timer:
class ChatPageState extends State<ChatPage> { Timer? timer; @override void initState() { super.initState(); // 监听聊天状态变化 context.read<ChatBloc>().stream.listen((state) { if (state.messages.isEmpty) { // 消息为空且没有运行中的Timer时才创建 if (timer == null) { _checkEmptyMessages(); timer = Timer.periodic(const Duration(seconds: 5), (t) => _checkEmptyMessages()); } } else { // 有消息直接销毁Timer if (timer != null) { timer!.cancel(); timer = null; } } }); } // 页面销毁时强制销毁Timer,避免内存泄漏 @override void dispose() { if (timer != null) { timer!.cancel(); timer = null; } super.dispose(); } void _checkEmptyMessages() { print('MES789 ${state.messages.isEmpty}'); if (state.messages.isEmpty) { add(ChatEventLoadFirstPage()); } else { if (timer != null) { timer!.cancel(); timer = null; } } } }
修改后即可保证始终只有一个Timer运行,有消息时能完全停止所有轮询逻辑。
内容的提问来源于stack exchange,提问作者L3odr0id
相关产品推荐
相关产品推荐

