I'm obtaining JSON data over HTTP and displaying it in a ListView. Since it's HTTP, it's all async.
Here's what I'd like to do:
var index = new ListView.builder(
controller: _scrollController,
itemBuilder: (ctx, i) async {
_log.fine("loading post $i");
var p = await _posts[i];
return p == null ? new PostPreview(p) : null;
},
);
Unfortunately, this doesn't work since IndexedWidgetBuilder has to be a synchronous function. How do I use a Future to build a child for an IndexedWidgetBuilder? It doesn't seem like there's a way to wait for the future to complete synchronously.
Previously, I was loading the data into an array and the IndexedWidgetBuilder function only checked to see if the list elements existed before returning the child widget.
var index = new ListView.builder(
controller: _scrollController,
itemBuilder: (ctx, i) {
_log.fine("loading post $i");
return _posts.length > i ? new PostPreview(_posts[i]) : null;
},
);
This works, but I would like to completely separate the view from the data and asynchronously request the JSON as needed.
This also seems, in my limited experience, like it might be a common use-case. Could an async version of IndexWidgetBuilder be added to flutter?
We put await in front of an asynchronous function to make the subsequence lines waiting for that future's result. We put async before the function body to mark that the function support await . An async function will automatically wrap the return value in Future if it doesn't already.
In Flutter, the FutureBuilder Widget is used to create widgets based on the latest snapshot of interaction with a Future. It is necessary for Future to be obtained earlier either through a change of state or change in dependencies.
You can wait for asynchronous computations using a FutureBuilder
. I'd probably change your PostPreview
to take a Future
as a constructor argument and put the FutureBuilder
there, but if you want to leave PostPreview
as-is, here's how to modify your itemBuilder
.
var index = new ListView.builder(
controller: _scrollController,
itemBuilder: (ctx, i) {
return new FutureBuilder(
future: _posts[i],
builder: (context, snapshot) {
return snapshot.connectionState == ConnectionState.done
? new PostPreview(snapshot.data)
: new Container(); // maybe a show placeholder widget?
);
},
);
The nice thing about FutureBuilder
is that it takes care of the scenarios where the async request completes and your State has already been disposed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With