![State.initState() must be a void method without an async
keyword.
how can i solve this probelms]1
@override
Future<void> initState() async {
// TODO: implement initState
super.initState();
_current_location();
BitmapDescriptor.fromAssetImage(
ImageConfiguration(devicePixelRatio: 2.5),
'assets/fff.png').then((onValue) {
pinLocationIcon = onValue;
});
//createCustomMarker(context);
// final Marker marker = Marker(icon: BitmapDescriptor.fromBytes(markerIcon));
DatabaseReference ref = FirebaseDatabase.instance.reference();
ref.child('users').once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> values = snapshot.value;
print(values.toString());
values.forEach((k, v) {
allMarkers.add(Marker(
markerId: MarkerId(k),
draggable: false,
icon: pinLocationIcon,
position: LatLng(v["latitude"], v["longitude"]),
infoWindow: InfoWindow(title: v["name"]),
onTap: () {
_onMarkerTapped(v["name"]);
},
),);
});
});
}
Sometimes, you may need to execute async code while initializing app. But Flutter will show an error if you add 'async' modifier to initState.
void initState() Called when this object is inserted into the tree. The framework will call this method exactly once for each State object it creates.
initState
must be a method which takes no parameters and returns void
. This is because it is overriding the method of the same name in the superclass (either StatelessWidget
or State<StatefulWidgetType>
. As such, this limitation is a contract which is fixed and binding; you cannot change it.
Of course, this also means that initState
cannot be marked as async
. This is because any method marked as async
will implicitly return a Future
, but if the method returns anything, then it cannot have a return type of void
which breaks the override contract.
If you need to call an async
method from within initState
, you can do so simply by not await
ing it:
@override
void initState() {
super.initState();
doSomeAsyncStuff();
}
Future<void> doSomeAsyncStuff() async {
...
}
If, however, you need the data from the async
method for your widget, you cannot simply wait for the Future
to return before you build the widget. Flutter does not allow this, because there is no telling how long it will take for the Future
to return, and stalling the widget building until then could potentially block your entire app.
Instead, you need to have your widget build normally and then have a way to notify your widget to update when the Future
has returned. This is most easily done with a FutureBuilder
:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: doSomeAsyncStuff(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
// Future hasn't finished yet, return a placeholder
return Text('Loading');
}
return Text('Loading Complete: ${snapshot.data}');
}
);
}
(Notice how instead of calling the async
method from initState
, I am calling it from the FutureBuilder
during the build process.)
EDIT: As pointed out, this approach only works in OP's situation where the awaited future will always eventually return a value. This is not always the case - sometimes the future doesn't return a value at all and is just a long-running process. Sometimes the future might return null instead of concrete data. And sometimes the future may result in an error instead of completing successfully. In any of these cases, snapshot.data
will be null after the future completes, in which case snapshot.hasData
will always be false.
In these situations, instead of depending on snapshot.hasData
to wait for data to appear, you can use snapshot.connectionState
to monitor the state of the future itself:
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: doSomeAsyncStuff(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
// Future hasn't finished yet, return a placeholder
return Text('Loading');
}
return Text('Loading Complete');
}
);
}
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