Flutter中Timer调用cancel()后仍后台运行报不安全查找祖先错误
彻底停止Flutter后台Timer的解决方案
问题根源
- 使用
ConsumerWidget(无状态组件)管理Timer,但无状态组件没有**dispose生命周期方法**,无法在组件销毁时主动终止Timer。 build方法会被多次触发(如父组件重建、状态更新),每次调用runTimerClock都会重建Timer;组件退出后,未被正确取消的Timer仍会后台运行,且回调中持有的WidgetRef已关联失效组件,从而触发Looking up a deactivated widget's ancestor is unsafe错误。
修正后的代码
将组件改为ConsumerStatefulWidget,利用State类的生命周期管理Timer,确保组件销毁时彻底终止Timer:
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; // 将Provider移到组件外部,避免每次创建组件时重复定义 final myStateProviderTime2 = StateProvider((ref) => 'state time'); class TimerClockQuestion extends ConsumerStatefulWidget { const TimerClockQuestion({super.key}); @override ConsumerState<TimerClockQuestion> createState() => _TimerClockQuestionState(); } class _TimerClockQuestionState extends ConsumerState<TimerClockQuestion> { Timer? timerClock2; String currentTime = '12:00 AM'; @override void initState() { super.initState(); // 仅在组件初始化时创建Timer runTimerClock(); } @override void dispose() { // 组件销毁时强制取消Timer,彻底终止后台任务 timerClock2?.cancel(); super.dispose(); } void runTimerClock() { // 先取消旧Timer,避免重复执行 timerClock2?.cancel(); timerClock2 = Timer.periodic(const Duration(seconds: 1), (timer) { currentTime = DateFormat('hh:mm:ss a').format(DateTime.now()); ref.read(myStateProviderTime2.notifier).state = currentTime; print(currentTime); }); } @override Widget build(BuildContext context) { currentTime = ref.watch(myStateProviderTime2); return Scaffold( body: Center( child: Text( currentTime, style: const TextStyle(fontSize: 50, color: Colors.white38), ), ), ); } }
关键修改说明
- 改用
ConsumerStatefulWidget:通过State类的initState初始化Timer,dispose方法在组件销毁时执行Timer取消操作,确保Timer生命周期与组件绑定。 - 避免
build重复创建Timer:将Timer初始化移至initState,防止build多次触发导致的Timer重复创建问题。 - 强制终止Timer:
dispose中的timerClock2?.cancel()是组件销毁时的最后保障,彻底停止后台运行的Timer,避免无效的ref调用。
内容的提问来源于stack exchange,提问作者Saad Mansoor
相关产品推荐
相关产品推荐

