Leave a rating/review
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 Future
s. 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 Future
s 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.