Flutter页面返回触发已卸载Widget状态异常,mounted判断无效求助
解决Widget已卸载时调用setState的异常
问题场景
为避免initState中调用服务报错,改用didChangeDependencies方法获取数据更新页面,页面加载正常,但返回上一页时触发异常:
Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
尝试过mounted状态判断、重写setState方法均无效,重写的setState代码如下:
@override void setState(VoidCallback fn) { if (mounted) { super.setState(fn); } }
相关业务代码:
List<DetailObjects?> onOdemeDetay = []; @override void didChangeDependencies() { super.didChangeDependencies(); OnOdemeListeClass().fetchList(context).then((value) { final checkData = Provider.of<LoginInfo>(context, listen: false); if (mounted) { setState(() { if (value != null && value.detailObjects != null) { onOdemeDetay = value.detailObjects!; checkData.updateLabel(onOdemeDetay[0]?.label); checkData.updateValue(onOdemeDetay[0]?.value); } }); } }); }
有效解决方案
1. 用CancelableOperation取消异步任务
在State类中维护异步任务的可取消实例,在Widget销毁时主动取消任务,避免回调执行时操作已卸载的State:
import 'package:async/async.dart'; CancelableOperation? _fetchOperation; @override void didChangeDependencies() { super.didChangeDependencies(); // 先取消已有任务,避免重复请求 _fetchOperation?.cancel(); _fetchOperation = CancelableOperation.fromFuture( OnOdemeListeClass().fetchList(context), ).then((value) { if (!mounted) return; final checkData = Provider.of<LoginInfo>(context, listen: false); setState(() { if (value != null && value.detailObjects != null) { onOdemeDetay = value.detailObjects!; checkData.updateLabel(onOdemeDetay[0]?.label); checkData.updateValue(onOdemeDetay[0]?.value); } }); }).catchError((error) { // 忽略任务取消的错误 if (error is OperationCanceledError) return; // 处理其他请求错误 }); } @override void dispose() { _fetchOperation?.cancel(); super.dispose(); }
2. 优化Provider调用与上下文判断
Flutter 3.7+支持直接通过context.mounted判断Widget状态,同时提前获取Provider实例,避免在异步回调中使用已失效的上下文:
@override void didChangeDependencies() { super.didChangeDependencies(); // 提前获取Provider实例,避免回调中使用无效context final checkData = Provider.of<LoginInfo>(context, listen: false); OnOdemeListeClass().fetchList(context).then((value) { if (!context.mounted) return; setState(() { if (value != null && value.detailObjects != null) { onOdemeDetay = value.detailObjects!; checkData.updateLabel(onOdemeDetay[0]?.label); checkData.updateValue(onOdemeDetay[0]?.value); } }); }); }
3. 控制请求仅触发一次
didChangeDependencies会在依赖变化时多次执行,添加标记避免重复发起请求:
bool _hasFetched = false; @override void didChangeDependencies() { super.didChangeDependencies(); if (!_hasFetched) { _hasFetched = true; // 执行请求逻辑... } }
核心原因
异步请求完成时Widget已卸载,mounted判断可能因时机问题失效,或回调中使用了已失效的上下文。通过主动取消异步任务、提前获取依赖、控制请求次数,可从根源避免异常。
内容的提问来源于stack exchange,提问作者macropyre
相关产品推荐
相关产品推荐

