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'),
);
}
}
I got this issue and I checked mounted
, now it's working fine.
{...
if(!mounted) return;
Navigator.of(context).pop();
...}
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);
...
}
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 showLoadingDialog
s were working and one wasn't -- so hopefully this guides somebody down a faster path to resolution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With