Complete Guide to FutureBuilder in Flutter

FutureBuilder in Flutter

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.

Image showing the Future as a Gift, representing the Future as a gift of type <T>. We can provide this Future to FutureBuilder and consume it's value when available.
A Future is like a package that is yet to be opened.

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:

  1. connectionState
  2. hasData
  3. hasError
  4. data
  5. 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?

Leave a Reply

Your email address will not be published. Required fields are marked *

Previous Post

Complete Guide to ValueNotifier in Flutter

Next Post
Sound Null Safety in Dart, Flutter essentials.

Null Safety in Dart, Flutter Essentials

Related Posts