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