Flutter WebViewWidget调用倒计时后持续刷新致崩溃问题求助
问题描述
在Flutter应用中使用WebViewWidget展示网页,在onPageFinished回调中调用倒计时方法后,出现WebView每秒刷新、最终应用崩溃的问题。
问题原因
- WebViewController重复创建:如果
controller在build方法中初始化,每次调用setState都会触发build重新执行,导致新的WebViewController被创建并调用loadRequest,WebView会重新加载页面,触发onPageFinished再次启动倒计时,形成无限循环,造成每秒刷新。 - Timer未正确管理:每次调用
startCountdownTimer都会创建新的Timer.periodic,旧Timer未被取消,多个Timer同时修改_secondsRemaining并触发setState,加剧页面刷新频率,最终导致内存泄漏和应用崩溃。
解决方案
- 将WebViewController初始化移至initState:确保controller只创建一次,避免每次build重新创建导致WebView重复加载。
- 添加Timer状态控制:启动新Timer前取消已有Timer,同时添加标志位确保倒计时只启动一次,避免重复触发。
- 在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
相关产品推荐
相关产品推荐

