How to use Future Builder Effectively in Flutter

Daniyal Dolare
4 min readJun 5, 2021

--

Most of the things in programming in general are synchronous i.e. they happen immediately or in constant time like adding two numbers and storing their sum into third variable is a synchronous task as addition happens immediately or in constant time. But some task in programming are asynchronous i.e. they don’t happen on time. For example, reading data from a file which is an input output task or consider any other I/O task, they take some time to complete which is not constant every time as a file can be already in use by other program, so the current program has to wait till file has been freed to access. So to handle such situations where a task can consume large amount of time and your app is unusable at that moment, we can use FutureBuilder.

In dart (flutter), A Future is used to represent a potential value, or error, that will be available at some time in the future. So by the time we get this future value, we can show some indicator to our user that the data is loading by using some progress indicator and let user know that app hasn’t freeze. So the Future Builder class takes a future that will complete in future and it takes a builder which gets build after the future has completed. You can also give a initialData which can be shown used until new data is received. So lets go through an example to understand it better.

Consider a task “onTime” which will always give you value on time. So when the user open the app, onTime will give the value to user immediately. Below is the function onTime which is synchronous and returns value immediately and does not increase the app loading and building time.

String onTime(){
return "I am always on time!";
}

Now consider a task “alwaysLate” which will always return value after a random time between 3 to 10 seconds. So when the user opens the app, the lazy data will be loaded after random time of 3–10 secs which can slow down loading of app and user will not be able to use app for that time or your app will crash if it try to access alwaysLate value when its null . Below is the code for function alwaysLate.

Future<String> alwaysLate() {
Duration duration = Duration(
seconds: 3 + Random().nextInt(7),
);
return Future.delayed(
duration, () => "It took me ${duration.inSeconds} sec to come!");
}

As onTime will directly return string value immediately, we can directly use it in Text widget. But we can’t do the same for alwaysLate as it is a future. So we will use Future builder which will build the required widgets only after future is completed.

FutureBuilder takes an argument future which is of type Future<String> in our case. Here flutter docs for FutureBuilder says that the future must be obtained or created earlier during State.initState, State.didUpdateWidget, or State.didChangeDependencies. It must not be created during the State.build or StatelessWidget.build method call else it will lead to unusual behaviour of infinite rebuild of FutureBuilder.

So firstly, we initialise a state variable of type late Future<String> lateValue and in our initState we call alwaysLate function and assign it to lateValue.

late Future<String> lazyValue;  //State variable for our future@override
void initState() {
super.initState();
lazyValue = alwaysLate();
}

Now we can use this future in our FutureBuilder to build widget as future is completed. As our data is of type string, we will be using FutureBuilder<String> .

FutureBuilder<String>(
future: lazyValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else {
return const CircularProgressIndicator();
}
},
),

The builder method takes BuildContext context and AsyncSnapshot<String> snapshot. Firstly we check if snapshot has data in it or not using sanpshot.hasData method. If it has data then we can build our Text widget with the data in the snapshot i.e. the lazyValue string. If there is no data yet in the snapshot, we can show a CircularProgressIndicator to let user know that something is loading.

So until when the future is completed, it will show a CircularProgressIndicator. When the future is completed, it will show the data from the future.

You can see the demonstration in this video.

Below is the full code for the app.

import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Colors.orange,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {late Future<String> lazyValue; //State variable for our future@override
void initState() {
super.initState();
lazyValue = alwaysLate(); //Setting future before widget building
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Working with Future"),
),
body: SafeArea(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(onTime()),
FutureBuilder<String>(
future: lazyValue,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!);
} else {
return const CircularProgressIndicator();
}
},
),
],
),
),
),
);
}

String onTime() {
return "I am always on time!";
}
Future<String> alwaysLate() {
Duration duration = Duration(
seconds: 3 + Random().nextInt(7),
);
return Future.delayed(
duration, () => "It took me ${duration.inSeconds} sec to come!");
}
}

--

--

Daniyal Dolare
Daniyal Dolare

Written by Daniyal Dolare

Future Engineer,Flutter Developer,Designer,Tech enthusiast.

No responses yet