Context
I am encountering an issue with FutureBuilder in Flutter where it recreates its Future on every widget rebuild, causing unexpected behavior in my app.
Specifically, I have a FutureBuilder that fetches a random number, but each time I trigger a rebuild (e.g., by pressing a button to update a counter), it generates a new random number instead of using the initially fetched value.
Problem
The issue arises when I try to update a counter with a button press. Each press not only updates the counter but also regenerates the random number displayed by the FutureBuilder. I want to maintain the first generated random number unless explicitly refreshed.
Here is a video representation of the problem:
Code
Here is the complete runnable program that demonstrates the problem:
import 'package:flutter/material.dart';
import 'dart:math'; // For generating random numbers
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'FutureBuilder Example',
home: FutureBuilderExample(),
);
}
}
class FutureBuilderExample extends StatefulWidget {
const FutureBuilderExample({super.key});
@override
_FutureBuilderExampleState createState() => _FutureBuilderExampleState();
}
class _FutureBuilderExampleState extends State<FutureBuilderExample> {
int counter = 0;
Future<int> fetchRandomNumber() async {
await Future.delayed(const Duration(milliseconds: 500));
return Random().nextInt(100);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('FutureBuilder with Random Number')),
body: Column(
children: [
Text('Counter: $counter'),
FutureBuilder<int>(
future:
fetchRandomNumber(), // Future is recreated here on every build
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
return Center(child: Text('Random Number: ${snapshot.data}'));
}
},
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
counter++; // Triggering rebuild
});
},
child: const Icon(Icons.add),
),
);
}
}
Question
I'm looking for a way to prevent the FutureBuilder from regenerating the future on each rebuild. How can I achieve this?
This question aims to serve as a canonical reference to address similar issues with FutureBuilder and StreamBuilder.

Explanation
The issue you're experiencing with the
FutureBuilderin Flutter is very common.The key point to understand here is that
FutureBuildershould be provided with afuturethat does not change on every build unless you specifically want the asynchronous operation to be re-performed.When you create the future directly inside the
FutureBuilder, it is re-created on every build (e.g. everysetState), which is why you are observing the random number changing with every button press.Solution: Using
initStateto Initialize theFutureThe solution is to initialize your future once and use this stable reference within FutureBuilder. This is usually achieved by defining the future in the
initStatemethod of yourStatefulWidget.Then, in your
FutureBuilder:Code example
Here's your complete refactored code snippet utilizing
initState:As you can now see, only the counter is updating, and not the random number:
Going further
I recommend that you watch this YouTube video on how to create a
FutureBuilderthe correct way. Where he explains your problem at 1:55 in the video.Another YouTube video by Randal Schwartz on the problem and how to solve it
This StackOverflow answer.