Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use async/HTTP data to return child widgets in an IndexedWidgetBuilder?

Tags:

flutter

dart

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?

like image 542
perlatus Avatar asked May 12 '17 18:05

perlatus


People also ask

How do you use async await in 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.

When should I use FutureBuilder?

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.


1 Answers

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.

like image 123
Collin Jackson Avatar answered Oct 09 '22 16:10

Collin Jackson