Louis Chovaneck
Louis Chovaneck

Reputation: 97

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

i would like to create a loader data, at the end the load of the data the screen will automaticly change the screen (with Navigator).

BUT i have some problem.

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

At the end of the method "getDataOfUser()" the "print(a)" executed fine but when it try to change the screen it crash and i have this error :

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'),
    );

  }

}

Upvotes: 9

Views: 15774

Answers (5)

Osama Remlawi
Osama Remlawi

Reputation: 2990

Try to rename you state class with underscore at the beginning _LoginScreenPresenter instead of LoginScreenPresenter

Another reason could produce this issue is when you @override Widget build(BuildContext context) rather than @override Widget buildPage(BuildContext context) or vise versa!

Upvotes: 0

sbanerjee
sbanerjee

Reputation: 1

I was using global state variable
final GlobalKey<State> _keyLoader = new GlobalKey<State>();

I was trying to pop the context using below line of code Navigator.of(_keyLoader.currentContext, rootNavigator: true).pop();

Since my code has many nested loop this code was giving me the error. I instead used below code to fix this error message

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

At times it is observed that in the nested loop the context is not correctly set when using global state variable and can lead to this error message.

Upvotes: 0

Sludge
Sludge

Reputation: 7395

If you are trying to implement a loading dialog while an action is being performed, be aware that if your dialog does not have time to actually build itself, it will throw this error.

The below example will likely fail because the showLoadingDialog and its corresponding pop have no delay between each other, so the context doesn't have time to exist in the showLoadingDialog yet:

///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();
            },
          ),

However, a delay of allowing the showLoadingDialog to build should allow the pop to work without the error showing:

/// 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();
            },
          ),

I'm not suggesting you add await Future.delayed... statements in your code to get your dialog to work correctly, but I initially couldn't figure out why some of the showLoadingDialogs were working and one wasn't -- so hopefully this guides somebody down a faster path to resolution.

Upvotes: 2

BIS Tech
BIS Tech

Reputation: 19434

I got this issue and I checked mounted, now it's working fine.

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

Upvotes: 6

Michael Yuwono
Michael Yuwono

Reputation: 2617

Your context was never assigned. You are calling Navigator using that context while it is still null. Try to assign it with the context from the page when it is built.

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

Upvotes: 5

Related Questions