Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

State.initState() must be a void method without an `async` keyword

Tags:

flutter

dart

![State.initState() must be a void method without an async keyword. how can i solve this probelms]1

how to solve this problem

@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"]);
          },
        ),);
      });
    });
  }
like image 213
Shihabmohamed Avatar asked May 13 '20 00:05

Shihabmohamed


People also ask

Can I use async in initState?

Sometimes, you may need to execute async code while initializing app. But Flutter will show an error if you add 'async' modifier to initState.

What is void initState in Flutter?

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.


1 Answers

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 awaiting 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');
   }
 );
}
like image 60
Abion47 Avatar answered Nov 22 '22 14:11

Abion47