I have a longList
where I need each element in the list to be sent to a database to return some a sub-list.
I then display each value in it’s own PageView
using PageView.builder.
and FutureBuilder
.
At first I was setting future: sql(longlist[pageIndex])
to give the future for each element in the PageView. However this is bad because it means the database is queried every time the widget is rebuilt.
So what I want is in the list for each element, call await sql(element)
in initState()
, and store this in a way the futurebuilder can use it.
Here is the simplified layout of my code:
final List<Map<String, dynamic>> longList; // <-- eg ["cat", "dog", "mouse", ...]
late Future<List<Map<String, dynamic>>> exampleFuture;
Future<List<Map<String, dynamic>>> getUnits(int index) async {
final data = await SQLHelper.getExamples(longList[0]["foo"]);
return data;
}
@override
void initState() {
super.initState();
exampleFuture = getUnits(0);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
itemCount: widget.longList.length,
itemBuilder: (context, pageIndex) {
print(pageIndex);
return FutureBuilder<List<Map<String, dynamic>>>(
future: exampleFuture[pageIndex],
builder: (BuildContext context,
AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
if (snapshot.hasData) {
List<Map<String, dynamic>>? exampleList = snapshot.data;
return Column(
children:[Text(
"this is page $pageIndex with future data "+exampleList[pageIndex];
),]
);
} else {
return const Center(child: CircularProgressIndicator());
}
}
);
},
),
);
}
}
I tried instead to create a list of futures in the initState but if the list is itself a future I can’t add elements to it and if it’s not a future (ie. it only holds a reference to each future) it doesn’t work with the futurebuilder as a future:
parameter. For example I tried:
late List<List<Map<String, dynamic>>> futureList;
void createList() async {
for (int i = 0; i<widget.longList.length; i++){
futureList.add(await SQLHelper.getExamples(widget.longList[i]["foo"]));
}
}
void initState() {
super.initState();
createList()
}
but trying to use it like
return FutureBuilder<List<Map<String, dynamic>>>(
future: futureList[pageIndex]
didn’t work and the futurebuilder thinks the list is empty.
Ideally I’d rather not use Future.wait
because I’d like to show the first page immediately without waiting for the rest of the db queries. If that’s the only solution I’d like to understand how to use it. I don’t get how I would use Future.await here.
2
Answers
You can have a list of futures. It just looks like perhaps you didn’t do it correctly. Here’s what it might look like:
Note the declaration for
futureList
:List<Future<...>>
, which is a list of futures.You can also use
typedef Unit = List<Map<String, dynamic>>
, to make things easier to understand.