NoSuchMethodError: The method 'ancestorStateOfType' was called on null with await and async method

NoSuchMethodError: The method 'ancestorStateOfType' was called on null with await and async method

我想创建一个loader数据,加载完数据屏幕会自动换屏(用Navigator)。

但是我有一些问题。

Unhandled Exception: NoSuchMethodError: The method 'ancestorStateOfType' was called on null.

在方法 "getDataOfUser()" 结束时,"print(a)" 执行得很好,但是当它尝试更改屏幕时它崩溃了,我有这个错误:

E/flutter (32148): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'ancestorStateOfType' was called on null.
E/flutter (32148): Receiver: null
E/flutter (32148): Tried calling: ancestorStateOfType(Instance of 'TypeMatcher<NavigatorState>')
E/flutter (32148): #0      Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
E/flutter (32148): #1      Navigator.of (package:flutter/src/widgets/navigator.dart:1446:19)
E/flutter (32148): #2      LoginScreenPresenter.initState.<anonymous closure> (package:test_app/login_presenter.dart:35:17)
class loginPresenter extends StatefulWidget {
  Vendeur v;
  loginPresenter({Key key, this.v}) : super(key: key);

  @override
  LoginScreenPresenter createState() => new LoginScreenPresenter();
}

class LoginScreenPresenter extends State<loginPresenter> {
  RestDatasource api = new RestDatasource();

  BuildContext context;

  bool finish = false;

  @override
  void initState() {
    getDataOfUser(widget.v).then((a) {
      print(a)
      Navigator.of(context).pushReplacement(new MaterialPageRoute(
          builder: (BuildContext context) => HomePage(
                v: widget.v,
              )));
    });

    super.initState();
  }

  Future<bool> getDataOfUser(Vendeur user) async {

    await api.getRegionsFromUser(user.idV).then((list) async {
      if (list != null) {
        for (var i = 0; i < list.length; ++i) {
          await DBProvider.db.newRegion(list[i], 1);
        }
      }
    });

    await api.getClientsFromUser(user.idV).then((list) async {
      if (list != null) {
        for (var i = 0; i < list.length; ++i) {
          await DBProvider.db.newClient(list[i], 1);
        }
      }
    });

    await api.getInterlocuteursFromUser(user.idV).then((list) async {
      if (list != null) {
        for (var i = 0; i < list.length; ++i) {
          await DBProvider.db.newInterlocuteurs(list[i], 1);
        }
      }
    });

    await api.getVisitesFromUser(user.idV).then((list) async {
      if (list != null) {
        for (var i = 0; i < list.length; ++i) {
          await DBProvider.db.newVisite(list[i], 1);
        }
      }
    });

    await api.getAvoirsFromUser(user.idV).then((list) async {
      if (list != null) {
        for (var i = 0; i < list.length; ++i) {
          if (list[i].deleted == 0) {
            await DBProvider.db.newAvoir(list[i], 1);
          }
        }
      }
    });

    await api.getRapportsFromUser(user.idV).then((list) async {
      if (list != null) {
        for (var i = 0; i < list.length; ++i) {
          await DBProvider.db.newRapport(list[i], user);
        }
      }
    });

    return true;
  }

  @override
  Widget build(context) {
    return RaisedButton(
      onPressed: () {
        Navigator.push(
            context,
            SlideRightRoute(
                widget: HomePage(
              v: widget.v,
            )));
      },
      child: Text('go'),
    );

  }

}

您的 context 从未分配过。您正在使用该上下文调用导航器,而它仍然为空。尝试在构建时为其分配页面中的上下文。

@override
Widget build(context) {
  setState(() => this.context = context);
  ...
}

我遇到了这个问题,我检查了 mounted,现在一切正常。

{...
  if(!mounted) return;
  Navigator.of(context).pop();
...}

如果您在执行操作时尝试实现加载对话框,请注意,如果您的对话框没有时间实际构建自身,它将抛出此错误。

下面的例子很可能会失败,因为 showLoadingDialog 和对应的 pop 之间没有延迟,所以 context 没有时间存在于 showLoadingDialog 还:

///DON'T DO THIS

  final GlobalKey<State> _loadingKey = GlobalKey<State>();

          ListTile(
            leading: Text("Sign Out"),
            onTap: () async {
              showLoadingDialog(context, _loadingKey);
              Navigator.of(_loadingKey.currentContext, rootNavigator: true)
                  .pop();
            },
          ),

但是,允许 showLoadingDialog 构建的延迟应该允许 pop 工作而不会显示错误:

/// This works without error

  final GlobalKey<State> _loadingKey = GlobalKey<State>();

          ListTile(
            leading: Text("Sign Out"),
            onTap: () async {
              showLoadingDialog(context, _loadingKey);
              await Future.delayed(Duration(seconds: 2));
              Navigator.of(_loadingKey.currentContext, rootNavigator: true)
                  .pop();
            },
          ),

我并不是建议您在代码中添加 await Future.delayed... 语句以使对话框正常工作,但我最初无法弄清楚为什么某些 showLoadingDialog 可以正常工作,并且一个不是 - 所以希望这可以引导某人更快地解决问题。

我正在使用全局状态变量
final GlobalKey<State> _keyLoader = new GlobalKey<State>();

我试图使用下面的代码行弹出上下文 Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();

因为我的代码有很多嵌套循环,所以这段代码给了我错误。我改为使用下面的代码来修复此错误消息

Navigator.of(context, rootNavigator: true).pop();

有时会发现,在嵌套循环中,使用全局状态变量时上下文设置不正确,可能会导致此错误消息。