Flutter: Correct approach to get value from Future
Moving this piece of code inside FutureBuilder
should resolve the issue.
getImagesPath().then((path){
imagesPath = path;
print(imagesPath); //prints correct path
});
So your final code should look like this:
@override
Widget build(BuildContext context) {
return Scaffold(
//removed
body: FutureBuilder<List>(
future: databaseHelper.getList(),
initialData: List(),
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, int position) {
getImagesPath().then((path){
imagesPath = path;
});
final item = snapshot.data[position];
final image = "$imagesPath/${item.row[0]}.jpg";
return Card(
child: ListTile(
leading: Image.file(File(image)),
title: Text(item.row[1]),
subtitle: Text(item.row[2]),
trailing: Icon(Icons.launch),
));
})
: Center(
child: CircularProgressIndicator(),
);
}));
}
Hope it helps!
I see that you have to build your widget from the output of two futures. You can either use two FutureBuilders
or have a helper method to combine them into one simplified code unit.
Also, never compute/invoke async function from build
function. It has to be initialized before (either in constructor or initState
method), otherwise the widget might end up repainting itself forever.
Coming to the solution: to simplify code, it is better to combine both future outputs into a single class as in the example below:
Data required for build
method:
class DataRequiredForBuild {
String imagesPath;
List items;
DataRequiredForBuild({
this.imagesPath,
this.items,
});
}
Function to fetch all required data:
Future<DataRequiredForBuild> _fetchAllData() async {
return DataRequiredForBuild(
imagesPath: await getImagesPath(),
items: await databaseHelperGetList(),
);
}
Now putting everything together in Widget:
Future<DataRequiredForBuild> _dataRequiredForBuild;
@override
void initState() {
super.initState();
// this should not be done in build method.
_dataRequiredForBuild = _fetchAllData();
}
@override
Widget build(BuildContext context) {
return Scaffold(
//removed
body: FutureBuilder<DataRequiredForBuild>(
future: _dataRequiredForBuild,
builder: (context, snapshot) {
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.items.length,
itemBuilder: (_, int position) {
final item = snapshot.data.items[position];
final image = "${snapshot.data.imagesPath}/${item.row[0]}.jpg";
return Card(
child: ListTile(
leading: Image.asset(image),
title: Text(item.row[1]),
subtitle: Text(item.row[2]),
trailing: Icon(Icons.launch),
));
})
: Center(
child: CircularProgressIndicator(),
);
},
),
);
}
Hope it helps.