问题
I am calling initial method to load data from API using initState. But it is resulting me an error. Here is error:
Unhandled Exception: inheritFromWidgetOfExactType(_LocalizationsScope) or inheritFromElement() was called before _ScreenState.initState() completed.
When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.
My code is:
@override
void initState() {
super.initState();
this._getCategories();
}
void _getCategories() async {
AppRoutes.showLoader(context);
Map<String, dynamic> data = await apiPostCall(
apiName: API.addUser,
context: context,
parameterData: null,
showAlert: false,
);
if(data.isNotEmpty){
AppRoutes.dismissLoader(context);
print(data);
}else {
AppRoutes.dismissLoader(context);
}
}
回答1:
You need to call _getCategories
after initState
has completed.
@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () {
this._getCategories();
});
// Could do this in one line: Future.delayed(Duration.zero, this._getCategories);
}
Also, you could do this on a different way, using addPostFrameCallback like showed in another answers.
回答2:
Use the didChangeDependencies method which gets called after initState.
For your example:
@override
void initState() {
super.initState();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
this._getCategories();
}
void _getCategories() async {
// Omitted for brevity
// ...
}
回答3:
Adding a frame callback might be better than using Future.delayed
with a zero duration - it's more explicit and clear as to what is happening, and this kind of situation is what frame callback was designed for:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
_getCategories();
});
}
回答4:
an alternative is to put it inside PostFrameCallback
which is between initState
and Build
so we can be sure that the initState
is already finished.
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) => getData());
super.initState();
}
getData() async {
}
回答5:
The best solution i think is use the context from the Widget build. And paste the method _getCategories(context) after the build with the context from the tree. So there is no problem with the widget tree.
回答6:
Use after_init package to handle this issue
Adds a didInitState()
lifecycle method to stateful widgets where you can safely access inherited widgets.
InheritedWidget
is heavily used throughout the Flutter framework. Many state management packages such as ScopedModel and Provider use it as well. Unfortunately, InheritedWidgets
are not accessible from the initState()
method of State
.
Example:
import 'package:flutter/material.dart';
import 'package:after_init/after_init.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: Example(),
),
),
);
}
class Example extends StatefulWidget {
@override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> with AfterInitMixin<Example> {
Size size;
/// This gets called first, as usual.
@override
void initState() {
super.initState();
// Your code here
}
/// This gets called after initState(), only once.
/// Safely access inherited widgets here.
@override
void didInitState() {
// No need to call super.didInitState().
// setState() is not required because build() will automatically be called by Flutter.
size = MediaQuery.of(context).size;
}
/// This gets called after didInitState().
/// And anytime the widget's dependencies change, as usual.
@override
void didChangeDependencies() {
super.didChangeDependencies();
// Your code here
}
/// Finally this gets called, as usual.
@override
Widget build(BuildContext context) {
return Center(
child: Text(size.toString()),
);
}
}
来源:https://stackoverflow.com/questions/56395081/unhandled-exception-inheritfromwidgetofexacttype-localizationsscope-or-inheri