In Flutter, you may have come across situations where you need to wait for a statement to execute. Asynchronous operations let your program complete work while waiting for another operation to finish. Some common examples are:
- Fetching Data From Internet
- Reading, Creating or Saving a File
- Instantiating Complex Objects
In Dart, to perform asynchronous operations, we use the Future
class, async
and await
keywords. To consume the Future in a widget we use the FutureBuilder widget.
Introduction to Futures π
A future is an instance of the Future
class in Dart. A future represents the result of an asynchronous operation and can have two states: uncompleted or completed.
We use the async
to declare a function as an asynchronous function, and its return type is automatically converted to a Future of the return data type. Here, on adding the async keyword the return type changes from String to Future<String>. Using the await keyword we wait for a response from any event which returns a Future. Here, the http.get
function returns a Future<Response>
.
import 'package:http/http.dart' as http;
Future<String> getData() async {
http.Response res = await http.get(Uri.parse("https://www.google.com");
return res.body;
}
Now at the place where we want to get the data, we will use the following code:
Future<void> main() async {
String data = await getData();
print(data);
}
Alternatively, we can also use the .then
keyword, using the following code:
void main(){
getData().then((value){
print(value);
});
}
Now that we have a basic understanding of Futures and when to use them. Let us see how to use them in our app.

You might also be interested in:
Traditional Asynchronous Method π¨βπ§
First, we will see how the code looks with the things we have learned till now. For our example, we will make an API request and see how the code looks. We will make a get request and no authentication is required in this case.
The API we will use is:
https://api.catboys.com/img
The response example:
{
"url": "https://cdn.catboys.com/images/image_73.jpg",
"artist": "CoverDesign1",
"artist_url": "https://www.deviantart.com/coverdesign1",
"source_url": "https://www.deviantart.com/coverdesign1/art/Artiste-Iya-Chen-Render-396950935",
"error": "none"
}
Prerequisites:
- Basic knowledge of
http
package and get Request. - Conversion of String JSON data to Map.
Code:
In the code, it is observable that the backend and frontend are tightly coupled. Also, we can see that we have to call setState((){})
again and again to update the state. We could use ValueNotifier
here, to update the loading and error state, but then we will have to manage the ValueNotifiers as well.
To handle all these states of loading, error and to reduce the boilerplate code, Flutter has a FutureBuilder widget.
Introduction to Future Builder π€
FutureBuilder is a widget that rebuilds itself based on the response from any Future function. The FutureBuilder subscribes to a Future and rebuilds when a value is received from the Future. It is Stateful in nature, i.e it internally manages its own state, as we do in Stateful widgets.
We use the following constructor to create FutureBuilder:
FutureBuilder({
Key? key,
this.future,
this.initialData,
required this.builder,
})
We pass the future value to the future
parameter. The builder
takes a function, which has two parameters BuildContext
, AsyncSnapshot<T>
and returns a Widget. The initialData
parameter is used to pass initial data to the FutureBuilder.
The implementation would look like this:
FutureBuilder(
future: getData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Container();
},
);
The AsyncSnapshot holds some of the important data regarding the connection, data, error, etc. Some of its important fields are:
- connectionState
- hasData
- hasError
- data
- error
ConnectionState:
The ConnectionState enum can have 4 possible values:
- none, maybe with some initial data.
- waiting, indicating that the asynchronous operation has begun, typically with the data being null.
- active, with data being non-null, and possible changing over time.
- done, with data being non-null.
After the connectionState
is ConnectionState.done
we can check if we have data or errors, using the hasData
and hasError
variables in the snapshot.
Future Builder Implementation π
This is the code where we consume the Future using FutureBuilder:
Note, how we don’t manage any of the loading or error states. The FutureBuilder internally handles the implementation for us and provides us an AsyncSnapshot. Find the complete code on Github.
Summary π
In the article, I explained the basics of Futures in Dart and we also viewed the 2 ways of implementing Futures in Flutter. We concluded that the FutureBuilder saves the trouble of maintaining loading and error state, it also helps to keep the code clean and readable. I hope I made you well versed with FutureBuilder and you will use it in your projects. Now that you have knowledge regarding Futures in Flutter, you might be interested to learn about Streams and StreamBuilder in Flutter.
If you have any queries you can comment below and I will be happy to help you. If you are new to Flutter check my post on how to install flutter on windows?