在 InitState 未处理异常中显示对话框:查找已停用小部件的祖先是不安全的
Posted
技术标签:
【中文标题】在 InitState 未处理异常中显示对话框:查找已停用小部件的祖先是不安全的【英文标题】:Show Dialog In InitState Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe 【发布时间】:2020-09-18 06:07:41 【问题描述】:第一次出现屏幕时,我想检查是否启用了用户 GPS 并授予了位置权限。然后,如果其中一个不满足,我会显示对话框以打开应用设置。
源代码
_initPermission(BuildContext context) async
final geolocationStatus = await commonF.getGeolocationPermission();
final gpsStatus = await commonF.getGPSService();
if (geolocationStatus != GeolocationStatus.granted)
showDialog(
context: context,
builder: (ctx)
return commonF.showPermissionLocation(ctx);
,
);
else if (!gpsStatus)
showDialog(
context: context,
builder: (ctx)
return commonF.showPermissionGPS(ctx);
,
);
然后我在 initState 中这样调用这个函数:
初始化状态
void initState()
super.initState();
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission(context));
问题是,每次屏幕出现时都会给我这样的错误:
错误
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
我做了什么:
像这样改变 InitState//1
WidgetsBinding.instance.addPostFrameCallback((_)
_initPermission(context);
);
//2
SchedulerBinding.instance.addPostFrameCallback((_) => _initPermission(context));
//3
Timer.run(()
_initPermission(context);
)
为脚手架添加全局键
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Scaffold(
key: _scaffoldKey,
搜索与我类似的问题
-
Show Dialog In Initstate
Looking up a deactivated widget's ancestor is unsafe
Load Data In Initstate
我做的结果什么都没有,第一次出现的时候还是出现错误。
但奇怪的是,这只发生在第一次出现屏幕时。当我执行 热重启 时,错误消息消失了。
[第一次出现屏幕失败]
[热重启,错误消失]
【问题讨论】:
【参考方案1】:我没有办法测试它(我没有 GPS 包)但尝试改变
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission(context));
到
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission()); //this inside the initstate
_initPermission() async
final geolocationStatus = await commonF.getGeolocationPermission();
final gpsStatus = await commonF.getGPSService();
if (geolocationStatus != GeolocationStatus.granted)
await showDialog(
context: context,
builder: (ctx) => commonF.showPermissionLocation
,
);
else if (!gpsStatus)
await showDialog(
context: context,
builder: (ctx) => commonF.showPermissionGPS
,
);
// the stateful widget can use the context in all its methods without passing it as a parameter
错误在热启动中消失,因为它只是刷新小部件的状态,但它已经创建(如果您进行热启动并在 initState 中打印一些内容,例如 print('This is init');,你不会看到它要么是因为刷新没有处理和初始化小部件,所以它不会再次运行那段代码)
编辑
根据您的要点,我只是做了一个可重现的最小示例,并在 DartPad 中运行没有问题,稍后我将在 VS 上尝试,但现在您可以检查是否有任何不同
enum GeolocationStatusgranted, denied //this is just for example
class MyWidget extends StatefulWidget
@override
_MyWidgetState createState() => _MyWidgetState();
class _MyWidgetState extends State<MyWidget>
showPermissionGPS()
return AlertDialog(
title: Text('GPSStatus'),
);
_showPermissionLocation()
return AlertDialog(
title: Text('Permission Localization'),
);
@override
initState()
super.initState();
Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission());
_initPermission() async
final geolocationStatus = await Future<GeolocationStatus>.value(GeolocationStatus.granted); //mocked future with a response to test
final gpsStatus = await Future<bool>.value(false); //mocked future with a response to test
if (geolocationStatus != GeolocationStatus.granted)
await showDialog(
context: context,
builder: (ctx) => _showPermissionLocation() //this mock commonF.showPermissionLocation and returns an AlertDialog
);
else if (!gpsStatus)
await showDialog(
context: context,
builder: (ctx) => _showPermissionGPS() //this mock commonF.showPermissionGPS and returns an AlertDialog
);
@override
Widget build(BuildContext context)
return Text('My text');
【讨论】:
已经尝试这个,它会产生新的错误'context != null': is not true.
。错误将指定给initState
和showDialog
commonF 来自哪个包?
commonF
是存储在 1 个文件中的所有分离函数。 gist.github.com/zgramming/2f431fdf1db72c7b9b6774017909a0eb
commonF.showPermissionGPS 和 commonF.showPermissionLocation 怎么样?是那些返回小部件的方法吗?我编辑了对话框的答案以返回该 ctx
gist.github.com/zgramming/2f431fdf1db72c7b9b6774017909a0eb 我更新了要点,使其更加清晰。 showPermissionGPS
& showPermissionLocation
它返回 alertDialog。可以在这里看到gist.github.com/zgramming/95fc8e55da2b9b85cb0fd57a24b840c6以上是关于在 InitState 未处理异常中显示对话框:查找已停用小部件的祖先是不安全的的主要内容,如果未能解决你的问题,请参考以下文章
来自 MFC 对话框中使用的托管 C# 用户控件的未处理异常