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
.