Flutter自动关闭Dialog并返回上页时遇组件销毁相关错误求助
问题分析与解决方案
错误原因
Error: Looking up a deactivated widget's ancestor is unsafe. 本质是因为异步延迟操作(Timer)执行时,对应的Widget上下文已经失效:
- Timer延迟2秒后执行回调时,Dialog的
buildContext可能已经被销毁,或者原页面的context对应的Widget已被标记为非活跃状态; - 手动关闭时,按钮点击触发的操作是同步的,此时上下文仍处于活跃状态,因此不会报错。
解决方案
方案1:添加上下文活跃状态判断(Flutter 3.0+)
在Timer回调中先检查mounted属性,确保上下文有效后再执行导航操作:
showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext buildContext) { Timer(const Duration(milliseconds: 2000), () { // 先确认Dialog上下文仍活跃,再关闭Dialog if (buildContext.mounted) { Navigator.of(buildContext).pop(); // 再确认原页面上下文活跃,再返回上一页 if (context.mounted) { context.router.navigateBack(); } } }); return AlertDialog( title: const Text(AppGlobals.invalidFieldsText), content: const SingleChildScrollView( child: Text(AppGlobals.invalidFieldsDescriptionText)), ); }, );
方案2:利用Dialog的then回调(更安全)
将Dialog关闭后的返回操作放在then回调中,确保Dialog完全关闭后再执行页面返回,同时单独用Timer控制Dialog的自动关闭:
// 先显示Dialog,关闭后触发then回调 showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext buildContext) { return AlertDialog( title: const Text(AppGlobals.invalidFieldsText), content: const SingleChildScrollView( child: Text(AppGlobals.invalidFieldsDescriptionText)), ); }, ).then((_) { // Dialog关闭后,检查原页面上下文有效性再返回 if (context.mounted) { context.router.navigateBack(); } }); // 延迟2秒关闭Dialog Timer(const Duration(milliseconds: 2000), () { if (context.mounted) { Navigator.of(context).pop(); } });
方案3:在Dialog内部管理Timer并及时取消(避免内存泄漏)
使用StatefulBuilder在Dialog内部创建Timer,并在回调执行后取消Timer,防止无效操作和内存泄漏:
showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext buildContext) { return StatefulBuilder( builder: (context, setState) { Timer? autoCloseTimer; autoCloseTimer = Timer(const Duration(milliseconds: 2000), () { if (buildContext.mounted) { Navigator.of(buildContext).pop(); if (context.mounted) { context.router.navigateBack(); } // 执行完成后取消Timer autoCloseTimer?.cancel(); } }); return AlertDialog( title: const Text(AppGlobals.invalidFieldsText), content: const SingleChildScrollView( child: Text(AppGlobals.invalidFieldsDescriptionText)), ); }, ); }, );
内容的提问来源于stack exchange,提问作者l.diazborg
相关产品推荐
相关产品推荐

