Flutter加载对话框无法关闭问题求助及代码排查
解决Flutter中加载对话框无法关闭且上下文错误的问题
嘿,我看你遇到了加载对话框关不掉还报上下文错误的问题,这其实是因为你用了已经被销毁的上下文来管理加载对话框,还有GlobalKey的使用方式不对导致的。咱们一步步来解决:
问题根源
- 失效的上下文传递:你在关闭AlertDialog的时候,用的是
dialogcontext(属于AlertDialog的上下文),然后把这个已经被销毁的context传给了_submit方法,用来显示加载对话框。这就导致后续操作的上下文已经不稳定,触发了那个"Looking up a deactivated widget's ancestor is unsafe"的错误。 - GlobalKey的不可靠性:依赖
_keyLoader来获取加载对话框的上下文是有风险的,因为当widget树更新或对话框被销毁时,这个key对应的context可能已经失效,导致无法正确关闭对话框。
修复方案
咱们直接去掉GlobalKey,改用当前有效的上下文来管理加载对话框的弹出和关闭,同时修正上下文传递的问题:
1. 修改_handleSubmit中的Ok按钮逻辑
把传给_submit的上下文改成原来的context(不是AlertDialog的dialogcontext),因为dialogcontext在AlertDialog关闭后就失效了:
onPressed: () async { Navigator.of(dialogcontext).pop(); // 先关闭确认对话框 await _submit(context, id); // 传递原来的有效上下文 },
2. 重构_submit方法,移除GlobalKey
直接在_submit里弹出加载对话框,并用当前上下文来关闭它,同时确保出错时也能关闭对话框:
Future<void> _submit(BuildContext context, int id) async { // 弹出加载对话框 showDialog( context: context, barrierDismissible: false, builder: (BuildContext dialogContext) { return WillPopScope( onWillPop: () async => false, // 禁止返回键关闭 child: SimpleDialog( children: [ Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation<Color>(Colors.pinkAccent[400]), ), SizedBox(height: 10), Text( "Please Wait...", style: TextStyle(color: Colors.pinkAccent[400]), ) ], ), ) ], ), ); }, ); try { // 调用数据获取方法 await getData(id, context); // 关闭加载对话框,使用rootNavigator确保能正确弹出 Navigator.of(context, rootNavigator: true).pop(); } catch (error) { print(error); // 出错时也要关闭对话框,避免一直显示 Navigator.of(context, rootNavigator: true).pop(); } }
3. (可选)简化Dialogs类
如果你还想保留Dialogs工具类,可以修改它让它不需要GlobalKey,直接用上下文来管理:
class Dialogs { static Future<void> showLoadingDialog( BuildContext context, String textToShow) async { return showDialog<void>( context: context, barrierDismissible: false, builder: (BuildContext dialogContext) { return WillPopScope( onWillPop: () async => false, child: SimpleDialog( children: <Widget>[ Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ CircularProgressIndicator( valueColor: AlwaysStoppedAnimation<Color>(Colors.pinkAccent[400]), ), SizedBox(height: 10), Text( textToShow, style: TextStyle(color: Colors.pinkAccent[400]), ) ], ), ) ], ), ); }, ); } }
然后在_submit里这样用:
Future<void> _submit(BuildContext context, int id) async { await Dialogs.showLoadingDialog(context, "Please Wait..."); try { await getData(id, context); Navigator.of(context, rootNavigator: true).pop(); } catch (error) { print(error); Navigator.of(context, rootNavigator: true).pop(); } }
关键注意点
- 永远不要传递已经被销毁的widget上下文(比如对话框关闭后的上下文)给后续操作。
- 避免用GlobalKey来管理对话框的上下文,直接使用当前有效的BuildContext更可靠。
- 一定要在
catch块里也关闭加载对话框,防止出错后对话框一直停留在界面上。
内容的提问来源于stack exchange,提问作者USER9561
相关产品推荐
相关产品推荐

