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

Flutter弹窗倒计时异常及Navigator调试锁报错求助

问题分析与解决方案

问题根源

  1. 倒计时跳变:原代码中StatefulBuilder的builder方法会在每次setState时重新执行,导致重复创建多个Timer.periodic,多个定时器同时修改倒计时秒数,造成跳变(如30→27→23)。
  2. _debugLocked错误:在Timer回调中直接调用Navigator导航操作(pop和引导页next),此时Navigator可能处于状态锁定状态(如正在构建Widget),触发断言失败。

修复方案

将弹窗封装为独立的StatefulWidget,规范定时器生命周期,并延迟执行导航操作避开锁定:

1. 创建独立的倒计时弹窗Widget

class CountdownDialog extends StatefulWidget {
  final VoidCallback onCountdownFinish;

  const CountdownDialog({super.key, required this.onCountdownFinish});

  @override
  State<CountdownDialog> createState() => _CountdownDialogState();
}

class _CountdownDialogState extends State<CountdownDialog> {
  late int countdownSeconds;
  late Timer countdownTimer;

  @override
  void initState() {
    super.initState();
    countdownSeconds = 30;
    // 仅在初始化时创建一次定时器,避免重复创建
    countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (mounted) {
        setState(() {
          if (countdownSeconds > 0) {
            countdownSeconds--;
          } else {
            _finishCountdown();
          }
        });
      } else {
        timer.cancel();
      }
    });
  }

  void _finishCountdown() {
    countdownTimer.cancel();
    // 延迟执行导航操作,避开Navigator锁定状态
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Navigator.of(context).pop();
      widget.onCountdownFinish();
    });
  }

  @override
  void dispose() {
    countdownTimer.cancel(); // 弹窗销毁时强制取消定时器,避免内存泄漏
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('Alarm'),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('Let\'s start measuring. Automatically closes in ${countdownSeconds} seconds.'),
          const SizedBox(height: 16),
          Text('Time remaining: ${countdownSeconds} seconds'),
        ],
      ),
      actions: [
        ElevatedButton(
          onPressed: () {
            countdownTimer.cancel();
            Navigator.of(context).pop();
            widget.onCountdownFinish();
          },
          child: const Text('close'),
        ),
      ],
    );
  }
}

2. 修改原弹窗调用方法

void _showCountdownDialog() {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (context) {
      return CountdownDialog(
        onCountdownFinish: () {
          _introKey.currentState?.next(); // 倒计时结束/手动关闭后跳转引导页下一页
        },
      );
    },
  );
}

关键修复点说明

  • 独立StatefulWidget:将弹窗逻辑封装后,initState仅执行一次,确保定时器只创建一个,彻底解决倒计时跳变问题。
  • 定时器生命周期管理:在dispose方法和弹窗关闭时主动取消定时器,避免内存泄漏。
  • 延迟导航操作:通过WidgetsBinding.instance.addPostFrameCallback延迟执行导航操作,确保在当前Widget帧构建完成后再修改Navigator状态,避开锁定断言。

内容的提问来源于stack exchange,提问作者luds

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:15:53