The await keyword in Flutter is not waiting

352

Solution 1

You have several problems in your code:

First of all, if you want to 'await' you have to use the word await when you want the flow to await. You do it in your _findFirstLocation() function but you are not doing it when you call it, hence, you should call it like this:

await _findFirstLocation();

But even this is not correct, because you are trying to block the UI thread, which is totally prohibited (this would cause the UI to freeze having a poor user experience).

In this cases, what you need is a FutureBuilder, in which you specify what should happen while your background process is running, what should happen when it throws an error and what should happen when the result is returned.

And lastly, I suggest you to not initialize variables in the build() method, as it can be called multiple times:

_useCaseManager = UseCaseManager.getInstance();

I would move that to the body of the class if possible, and when not possible put it in the initState() method.

Solution 2

You do not await the method _findFirstLocation(); where you call it. That means the call will not wait for the result, it will just go to the next instruction and continue with that.

In this special case, you cannot actually await it because the build method is not async and you cannot change that. In this case, you need a FutureBuilder to show something like a spinner or wait dialog until your results are loaded.

You can find more information here:

What is a Future and how do I use it?

Share:
352
Christopher
Author by

Christopher

Updated on December 26, 2022

Comments

  • Christopher
    Christopher over 1 year

    I am learning Dart and Flutter with a small mobile application. I have read everything I found about the await keyword but I still have problems I don't understand. Below the simplified code. I removed everything I thought it is unnessecary for understanding my problem. If something important is missing, please tell me.

    My problem is the following line below the TODO (line 7): List locations = await _useCaseManager.findLocations(); In this method I query the database. I want the application to wait until the query is finished and the data are returned.

    I call the method _findFirstLocation() in the build() method. But Flutter does not wait for the data. It goes on with the rest of the code, especially with the method createNextAppointmentsList(). In this method I need the data the application should wait for for the future - the attribute _selectedLocation. But because Flutter is not waiting, _selectedLocation is null.

    This is the relevant part of the class.

    class _AppointmentsOverviewScreenState extends State<AppointsmentsOverviewScreen> {
      UseCaseManager _useCaseManager;
      Location _selectedLocation;
    
      void _findFirstLocation() async {
        // TODO Hier wartet er schon wieder nicht.
        List<Location> locations = await _useCaseManager.findLocations();
        _selectedLocation = locations.first;
        print(_selectedLocation);
      }
    
      @override
      Widget build(BuildContext context) {
        _useCaseManager = UseCaseManager.getInstance();
        _findFirstLocation();
        
        return Scaffold(
          appBar: AppBar(
            title: Text(LabelConstants.TITLE_APPOINTMENT_OVERVIEW),
          ),
          body: Column(
            children: <Widget>[
              Container(child: createNextAppointmentsList(),)
            ],
          ),
        );
      }
    
      Widget createNextAppointmentsList() {
        return FutureBuilder<List<Appointment>>(
          future: _useCaseManager.findAppointmentsForActiveGarbageCans(_selectedLocation.locationId),
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data.length,
                itemBuilder: (BuildContext context, int index) {
                  return ListTile(title: Text(snapshot.data[index].garbageCanName),
                    subtitle: Text(snapshot.data[index].date),
                  );
                },
              );
            } else if (snapshot.hasError) {
              return Text(snapshot.error.toString());
            }
            return Center(child: CircularProgressIndicator());
          },
        );
      }
    }
    

    In the method _findFirstLocation there is the following method with a database query called.

      Future<List<Location>> findLocations() async {
        final db = await database;
    
        final List<Map<String, dynamic>> maps = await db.query(DatabaseConstants.LOCATION_TABLE_NAME);
        
        return List.generate(maps.length, (i) {
          Location location = Location(
            locationId: maps[i][DatabaseConstants.COLUMN_NAME_LOCATION_ID],
            street: maps[i][DatabaseConstants.COLUMN_NAME_STREET],
            houseNumber: maps[i][DatabaseConstants.COLUMN_NAME_HOUSENUMBER],
            zipCode: maps[i][DatabaseConstants.COLUMN_NAME_ZIP_CODE],
            city: maps[i][DatabaseConstants.COLUMN_NAME_CITY],
          );
          return location;
        });
      }
    

    Because I have had already problems with await and the cause for these problems was a foreach() with a lambda expression, I tried another type of for loop as alternative:

      Future<List<Location>> findLocations() async {
        final db = await database;
    
        final List<Map<String, dynamic>> maps = await db.query(DatabaseConstants.LOCATION_TABLE_NAME);
        final List<Location> locations = List();
    
        for (int i = 0; i < maps.length; i++) {
          var locationFromDatabase = maps[i];
          Location location = Location(
              locationId: maps[i][DatabaseConstants.COLUMN_NAME_LOCATION_ID],
              street: maps[i][DatabaseConstants.COLUMN_NAME_STREET],
              houseNumber: maps[i][DatabaseConstants.COLUMN_NAME_HOUSENUMBER],
              zipCode: maps[i][DatabaseConstants.COLUMN_NAME_ZIP_CODE],
              city: maps[i][DatabaseConstants.COLUMN_NAME_CITY],
          );
          locations.add(location);
        }
        return locations;
    }
    

    But in both cases, the application is not waiting for the data and I don't understand the reason.

    Thank you in advance.

    Christopher

  • Christopher
    Christopher over 3 years
    Thank you very much for the improvements of my code. I see I haven't still understood everything. But therefore I am still practising with a small app.
  • Christopher
    Christopher over 3 years
    Thank you very much. I wasn't aware of the build method.