Flutter 在InitState未处理异常中显示对话框:查找已停用的小部件';他的祖先是不安全的

Flutter 在InitState未处理异常中显示对话框:查找已停用的小部件';他的祖先是不安全的,flutter,Flutter,第一次出现屏幕时,我想检查用户GPS是否启用,位置权限是否授予。然后,如果其中一个未实现,我将显示对话框以打开应用程序设置 源代码 然后我在initState中调用了这个函数,如下所示: 初始状态 问题是,每次屏幕出现时,都会出现如下错误: 错误 我所做的: 像这样改变你的状态 为Scaffold添加全局键 final GlobalKey _scaffoldKey=GlobalKey(); 脚手架( 钥匙:_scaffoldKey, 寻找与我相似的问题 我所做的结果是什么都

第一次出现屏幕时,我想检查用户GPS是否启用,位置权限是否授予。然后,如果其中一个未实现,我将显示对话框以打开应用程序设置

源代码 然后我在initState中调用了这个函数,如下所示:

初始状态 问题是,每次屏幕出现时,都会出现如下错误:

错误 我所做的:

  • 像这样改变你的状态
  • 为Scaffold添加全局键
final GlobalKey _scaffoldKey=GlobalKey();
脚手架(
钥匙:_scaffoldKey,
  • 寻找与我相似的问题
我所做的结果是什么都没有,错误仍然出现在第一次出现的屏幕上

但奇怪的是,这种情况只有在第一次出现屏幕时才会发生。当我执行热重启时,错误消息就消失了

[首次出现屏幕时失败]

[热重启,错误消失]

我没有办法测试它(我没有GPS软件包),但请尝试更换

Future.delayed(Duration(milliseconds: 50)).then((_) => _initPermission(context));

该错误在热重启中消失,因为它只是刷新小部件的状态,但它已经被创建(如果您在initState中执行热重启并打印某些内容,例如print('This is init');您也不会看到它,因为刷新不会处理和初始化小部件,因此它不会再次运行该代码段)

编辑

根据你的要点,我刚刚制作了一个最小的可复制示例,在DartPad中运行时没有问题,稍后我将在VS上尝试,但现在你能检查一下是否有什么不同吗

enum GeolocationStatus{granted, 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');
  }
}
enumgeolocationstatus{grated,denied}//这只是一个例子
类MyWidget扩展了StatefulWidget{
@凌驾
_MyWidgetState createState()=>\u MyWidgetState();
}
类_MyWidgetState扩展状态{
showPermissionGPS(){
返回警报对话框(
标题:文本(“GPSStatus”),
);
}
_showPermissionLocation(){
返回警报对话框(
标题:文本(“权限本地化”),
);
}
@凌驾
initState(){
super.initState();
Future.delayed(持续时间(毫秒:50))。然后(()=>_initPermission());
}
_initPermission()异步{
final geolocationStatus=await Future.value(geolocationStatus.grated);//模拟未来并响应测试
final gpsStatus=await Future.value(false);//模拟未来并响应测试
if(geolocationStatus!=geolocationStatus.grated){
等待显示对话框(
上下文:上下文,
生成器:(ctx)=>\u showPermissionLocation()//此模拟commonF.showPermissionLocation并返回AlertDialog
);
}否则如果(!gpsStatus){
等待显示对话框(
上下文:上下文,
生成器:(ctx)=>\u showPermissionGPS()//此模拟commonF.showPermissionGPS并返回AlertDialog
);
}
}
@凌驾
小部件构建(构建上下文){
返回文本(“我的文本”);
}
}

已尝试此操作,它将产生新的错误
'context!=null':不正确。
错误将指定为
initState
showDialog
commonF是从哪个包来的?
commonF
是我存储在一个文件中的所有分离函数。commonF.showPermissionGPS和commonF.showPermissionLocation如何?这些是吗返回小部件的方法?我编辑了对话框的答案以返回ctx,我更新了要点,使其更加清晰。
showPermissionGPS
&
showPermissionLocation
it return alertDialog。可在此处查看
[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.
//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,
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
enum GeolocationStatus{granted, 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');
  }
}