What is FutureBuilder in Flutter?
FutureBuilder is a widget that builds itself based on the latest snapshot of interaction with a Future. It lets you handle asynchronous operations (like network calls, database queries, or file I/O) and update the UI automatically when the future completes – whether it succeeds with data or fails with an error.
Basic Usage
To use FutureBuilder, you provide a future and a builder function. The builder is called whenever the future's state changes. It receives a BuildContext and an AsyncSnapshot which contains the current state (loading, data, error).
Understanding AsyncSnapshot
The AsyncSnapshot object passed to the builder contains all the information about the asynchronous operation:
- connectionState: One of
ConnectionState.none(no future started),ConnectionState.waiting(future is in progress),ConnectionState.active(for streams), orConnectionState.done(future completed). - hasData: Whether the snapshot contains non‑null data (i.e., the future completed successfully).
- data: The value returned by the future (only available when
hasDatais true). - hasError: Whether the future completed with an error.
- error: The error object (only available when
hasErroris true).
Building UI for Different States
A typical pattern is to handle three states: waiting (loading), error, and data. Here's a more detailed example:
Handling Errors Gracefully
Always check snapshot.hasError before accessing snapshot.data. You can also provide a custom error widget or a retry button.
Important: Where to Create the Future
Never create the Future directly inside the build method, because that would create a new Future on every rebuild, causing the FutureBuilder to reset and re‑trigger the async operation continuously. Instead, store the Future in a state variable (or use a Future that doesn't change, like from a repository).
When the Future Changes
If you need to update the future (e.g., after a user action), assign a new Future to the variable and call setState. The FutureBuilder will automatically listen to the new Future.
Common Mistakes Beginners Make
- Creating the future inside
build: Leads to infinite rebuilds and wasted resources. - Not handling all connection states: For example, showing a loading indicator only when
connectionState == ConnectionState.waitingis correct, but forgetting thatConnectionState.activemight also be relevant for streams. - Accessing
snapshot.datawithout checkinghasData: Causes a null safety error if the future hasn't completed yet. - Ignoring errors: Always show a user‑friendly message or a retry option.
- Assuming
snapshot.datais non‑null whenconnectionState == ConnectionState.done: It might still be null if the future returned null. CheckhasDatainstead. - Not using
FutureBuilderfor simple one‑time operations: Sometimes aFuturewiththenandcatchErrorinsideinitStateplussetStateis simpler, but FutureBuilder is declarative and handles state automatically.
Key Points to Remember
- FutureBuilder rebuilds automatically when the future's state changes.
- Always check
snapshot.connectionStateandsnapshot.hasData/snapshot.hasErrorbefore using the data. - Store the future outside the
buildmethod (e.g., ininitState) to avoid recreating it. - Use
ConnectionState.waitingto show a loading indicator. - Handle errors gracefully with user feedback and optional retry.
- For streams, use
StreamBuilderwhich works similarly.
Common Interview Questions
- How does FutureBuilder work internally?
- What is the difference between
ConnectionState.waitingandConnectionState.done? - Why should you avoid creating the
Futureinside thebuildmethod? - How would you implement a retry button with FutureBuilder?
- Can FutureBuilder be used with a
Futurethat never completes? What happens? - How do you handle both data and error states in a FutureBuilder?
- What is the purpose of
AsyncSnapshot?