я хотел бы создать загрузчик данных, в конце загрузки данных экран автоматически изменит экран (с навигатором).
НО у меня есть проблема.
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
никогда не назначался. Вы вызываете Navigator, используя этот контекст, пока он все еще равен нулю. Попробуйте присвоить ему контекст со страницы при его построении.
@override
Widget build(context) {
setState(() => this.context = 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();
Время от времени наблюдается, что во вложенном цикле контекст неправильно установлен при использовании глобальной переменной состояния и может привести к этому сообщению об ошибке.
Привет, у меня похожий случай, но у меня другая структура, пожалуйста, помогите. Стараюсь не задавать новый вопрос. Вот мой код: codepen.io/easy-pbnl/pen/BaNaQpX Строка 37, где проблема, пожалуйста, как мне установить контекст в этой точке?