I have a custom FLutter widget that receives a future as a parameter to it’s constructor and has FutureBuilder
inside.
I want to add the ability to rerun this future in case of connection error, but the problem is that future after first usage is "exhausted". So I need some way to create a copy of the future passed as a parameter to use the copy inside FutureBuilder
every time user press the Reload button.
import 'package:flutter/material.dart';
class CustomFutureBuilder<T> extends StatefulWidget {
final Future<T> future;
const CustomFutureBuilder({super.key, required this.future});
@override
State<CustomFutureBuilder<T>> createState() => _CustomFutureBuilderState<T>();
}
class _CustomFutureBuilderState<T> extends State<CustomFutureBuilder<T>> {
late Future<T> _future;
@override
void initState() {
// I need to use initState to initialize _future for the first usage of this widget
_future = widget.future; // ← here I want to create a future clone and use it instead of original
super.initState();
}
@override
void didUpdateWidget(covariant CommonFutureBuilder<T> oldWidget) {
_future = widget.future; // ← and here too
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _future,
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const LinearProgressIndicator();
}
if (snapshot.hasError) {
debugPrint('Loading error: ${snapshot.error}');
return Column(
children: [
const Text(
'Loading error is occurred. Check the internet connection or try again later.'),
OutlinedButton(
onPressed: () {
setState(() {
// ← and maybe here too, I am not sure
});
},
child: const Text('Reload'),
),
],
);
}
final data = snapshot.data as T;
return …
},
);
}
}
2
Answers
You can try
StreamBuilder
replaceFutureBuilder
, becauseFuture
can’t listen to a variable change. It’s a one-time response. Instead, you’ll need to use aStream
for refresh or event by user.This is code for your case :
function for refresh :
You can’t. One way to solve this is instead of injecting a
Future<T>
you inject a factory producing aFuture<T>
.So instead of
_future
getting passed into your constructor, pass aFunction(Future<T>) futureFactory
.In your InitState you need to call it once:
And then when someone wants to run the future again, you do the same thing:
You cannot rerun a future, but if you have a way to create those futures, you are good to go.