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

Flutter WebViewWidget调用倒计时后持续刷新致崩溃问题求助

问题描述

在Flutter应用中使用WebViewWidget展示网页,在onPageFinished回调中调用倒计时方法后,出现WebView每秒刷新、最终应用崩溃的问题。

问题原因
  • WebViewController重复创建:如果controller在build方法中初始化,每次调用setState都会触发build重新执行,导致新的WebViewController被创建并调用loadRequest,WebView会重新加载页面,触发onPageFinished再次启动倒计时,形成无限循环,造成每秒刷新。
  • Timer未正确管理:每次调用startCountdownTimer都会创建新的Timer.periodic,旧Timer未被取消,多个Timer同时修改_secondsRemaining并触发setState,加剧页面刷新频率,最终导致内存泄漏和应用崩溃。
解决方案
  1. 将WebViewController初始化移至initState:确保controller只创建一次,避免每次build重新创建导致WebView重复加载。
  2. 添加Timer状态控制:启动新Timer前取消已有Timer,同时添加标志位确保倒计时只启动一次,避免重复触发。
  3. 在dispose中取消Timer:防止页面销毁后Timer仍在运行,造成内存泄漏。
修改后的代码示例

State类完整代码

class _YourPageState extends State<YourPage> {
  int _secondsRemaining = 300; // 5分钟(300秒)
  late Timer _timer;
  late WebViewController controller;
  bool _countdownStarted = false; // 标记倒计时是否已启动

  @override
  void initState() {
    super.initState();
    // 在initState中初始化WebViewController,确保只创建一次
    controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setBackgroundColor(const Color(0x00000000))
      ..setNavigationDelegate(
        NavigationDelegate(
          onProgress: (int progress) {
            debugPrint('WebView加载中(进度:$progress%)');
          },
          onPageStarted: (String url) {
            debugPrint('页面开始加载:$url');
          },
          onPageFinished: (String url) {
            debugPrint('页面加载完成:$url');
            // 只有倒计时未启动时才启动
            if (!_countdownStarted) {
              startCountdownTimer();
            }
          },
          onWebResourceError: (WebResourceError error) {
            debugPrint('''
页面资源错误:
  错误码:${error.errorCode}
  描述:${error.description}
  错误类型:${error.errorType}
  是否为主框架:${error.isForMainFrame}
            ''');
          },
          onNavigationRequest: (NavigationRequest request) {
            if (request.url.startsWith('myurl')) {
              debugPrint('阻止导航到:${request.url}');
              return NavigationDecision.prevent;
            }
            debugPrint('允许导航到:${request.url}');
            return NavigationDecision.navigate;
          },
          onUrlChange: (UrlChange change) {
            debugPrint('URL变更为:${change.url}');
          },
        ),
      )
      ..addJavaScriptChannel(
        'Toaster',
        onMessageReceived: (JavaScriptMessage message) {
          debugPrint("消息:$message");
          print(message.message);
          var res = json.decode(message.message);
        },
      )
      ..loadRequest(Uri.parse("Myurl"));
  }

  void startCountdownTimer() {
    // 先取消已存在的Timer,避免多个Timer同时运行
    if (_timer.isActive) {
      _timer.cancel();
    }
    _countdownStarted = true;
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        if (_secondsRemaining > 0) {
          _secondsRemaining--;
        } else {
          timer.cancel();
        }
      });
    });
  }

  String getFormattedTime() {
    final minutes = (_secondsRemaining / 60).floor();
    final seconds = _secondsRemaining % 60;
    return '$minutes:${seconds.toString().padLeft(2, '0')}';
  }

  @override
  void dispose() {
    // 页面销毁时取消Timer,防止内存泄漏
    _timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          Align(
            alignment: Alignment.topCenter,
            child: Container(
              padding: const EdgeInsets.all(5),
              decoration: BoxDecoration(
                color: Colors.black.withOpacity(0.5),
                borderRadius: BorderRadius.circular(0),
              ),
              child: Text(
                '剩余时间: ${getFormattedTime()}',
                style: const TextStyle(
                  fontFamily: 'Montserrat',
                  fontSize: 15,
                  color: Colors.white,
                  fontWeight: FontWeight.bold,
                ),
                textAlign: TextAlign.justify,
              ),
            ),
          ),
          WebViewWidget(controller: controller),
        ],
      ),
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 11:21:09