Inside the Widget build(BuildContext context) function, you will notice that when rendering a Widget, we cannot directly use async / await or .then() from a Future and wait for the data to arrive before displaying it.
The use cases we are typically interested in include calling Web Services or querying a Database. In these scenarios, we often want to evaluate the retrieved value before rendering the UI. For example, if the received value is null, we might want to render a TextField widget to let the user input data; but if it is not null, we render a Text widget to display the result.
If we try to do this using standard synchronous methods, we won't be able to achieve the desired outcome. However, in Flutter, there is a class specifically designed to help solve this problem: FutureBuilder.
FutureBuilder({Key key, Future<T> future, T initialData, @required AsyncWidgetBuilder<T> builder })
FutureBuilder accepts 3 main parameters:
-
future: The Future object representing the asynchronous computation associated with the builder. -
initialData: The initial snapshot data to display before the Future finishes executing. -
builder: AnAsyncWidgetBuilder, which is a function used to build the Widget based on the asynchronous state.
The builder function itself takes 2 parameters: BuildContext context and AsyncSnapshot<T> snapshot, and it must return a Widget.
The AsyncSnapshot contains the following properties:
-
connectionState: An enum value ofConnectionStatethat represents the current status of the asynchronous connection. The possible states includenone,waiting,active, anddone. -
data: The latest data received from the asynchronous computation. -
error: The latest error encountered during the asynchronous computation. -
hasDataandhasError: Boolean properties used to easily check if the snapshot contains valid data or an error.
Example Usage
class RequestSender extends StatelessWidget {
RequestSender(this.url, {Key key}) : super(key: key);
final String url;
@override
Widget build(BuildContext context) {
return new Container(
padding: const EdgeInsets.all(10.0),
child: FutureBuilder(
future: url != null
? http.get(url).then((response) => response.body)
: null,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Input a URL to start');
case ConnectionState.waiting:
return new Center(child: new CircularProgressIndicator());
case ConnectionState.active:
return new Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return new Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return new ListView(
children: <Widget>[new Text(snapshot.data)]);
}
}
}));
}
}
Reference: https://flutter-academy.com/async-in-flutter-futurebuilder/