【问题标题】:Show Dialog In InitState Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe在 InitState 未处理异常中显示对话框:查找已停用小部件的祖先是不安全的
【发布时间】: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,

我做的结果什么都没有,第一次出现的时候还是出现错误。

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

[第一次出现屏幕失败]

[热重启,错误消失]

【问题讨论】:

    标签: flutter


    【解决方案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 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');
      }
    }
    

    【讨论】:

    猜你喜欢
    • 2020-06-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2020-08-08
    • 2021-11-15
    • 2021-06-03
    • 2020-12-26
    • 2022-06-26
    相关资源
    最近更新 更多