Flutter UI Widgets

Nov 9 2021 Dart 2.14, Flutter 2.5, VS Code 1.61

Part 1: Flutter UI Widgets

7. Use the FutureBuilder Widget

Episode complete

Play next episode

Next
About this episode
See versions

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 6. Work with BottomNavigationBar Next episode: 8. Style Your App with Themes

At 03:31, the ListView.builder is supposed to use the snapshot’s data instead of the articles variable. So the ListView.builder should look like this:

return ListView.builder(
  itemCount: snapshot.data!.length,
  itemBuilder: (BuildContext context, int index) {
    return ArticleCard(article: snapshot.data[index]);
  },
);

In Dart programming language, asynchronous tasks are handled with a Future or a Stream. We would be focusing on Futures. A Future is used when you want to perform time consuming tasks where the data is not returned immediately. These could be stuffs like reading a file or downloading contents over the internet.

These tasks dont return their values immediately. Instead they return some time in the future; hence the name Future. According to dart’s documentation: A Future is “An object representing a delayed computation.”

Flutter, provides us with the FutureBuilder widget that helps handle Futures effectively. The Future can be completed with either a value or an error. The FutureBuilder handles all these states without the need for us to manually call setState().

Back in VSCode, convert the HomePage widget to a Stateful widget and add the following code:

Future<List<Article>> futureArticles;

@override
void initState() {
  super.initState();
  futureArticles = ArticleRepo().getArticles();
}

Here, we added futureArticles as a member of the State object. It is a Future of type List of Articles. Meaning, it is going to hold a List of Articles that would be returned sometime in the future.

Next, we override theinitState() method which is a method of the State class. This method is called when this widget is inserted into the widget tree and it is called only once. We use this method to initialize or execute on-off operations once the widget is mouted. In this case, we initialize the futureArticles variable to ArticleRepo().getArticles() which returns a Future that is a List of Articles.

Click on the ArticleRepo class and press the F12 key to go to its definition. The ArticleRepo class is a Repository. The repository is where the data access logic is stored. It hides the businees logic and provides a simple layer for data access. This is called the “Repository Pattern.” To view the business logic, click on ArticleAPI and press the F12 key.

The fetchArticles() mocks an online request. A success boolean is provided.

If it is set to true then we return a Future that would be delayed for some seconds before the value is sent. This is just used to simulate an actual network delay. Here, we use Future.delayed() constructor to achieve this. The value sent is still the same articles variable that stores the List of Articles from the model file.

Okay, lets head back to the HomePage widget and update it to use a FutureBuilder. Update your build method to the following:

return FutureBuilder<List<Article>>(
  future: futureArticles,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return ListView.builder(
        // key: PageStorageKey<String>('articles_list'),
        itemCount: snapshot.data!.length,
        itemBuilder: (BuildContext context, int index) {
          return ArticleCard(article: snapshot.data[index]);
        },
      );
    }
    if (snapshot.hasError) {
      return Center(
        child: Text(
          '${snapshot.error}',
          style: const TextStyle(fontSize: 24),
        ),
      );
    }
    return const Center(
      child: CircularProgressIndicator(),
    );
  },
);

This returns a FutureBuilder that expects a List of Articles. We pass in the future we initialized previously in the initState method. The builder is called whenever the value of the future changes. The FutureBuilder widget uses the builder to update the widget based on different snapshots of the Future. A snapshot is just a representation of the most recent interaction with the asynchronous task. So simply contains information of different scenarios like the data, the connection state, the error and other checks for the asynchronous tasks.

Remember, a Future can return a value or and error and these are different data is contained inside the snapshot supplied by the FutureBuilder. In this code, we check to see if the snapshot has received data from the Future and if yes, we return the ListView. If it returns an error, then we return an error text.

And finally, if none of these conditions are met, we return a CircularProgressIndicator which shows that we are awaiting the result. Save this file and do a hot restart. You do a hot restart because the initState is called only once and this is when the widget is added to the tree. You can see a loading spinner and the result is shown after some delay.

Finally, let’s check to see what the error state looks like. Let’s head over to the ArticleAPI class and change the boolean property to false. Do a hot restart. And you can see the error state.