Reputation: 105
I would like to run a downloading Future function when opening a page in flutter, however it is being called multiple times.
I would like to implement a solution like the second in this article:
https://flutterigniter.com/future-async-called-multiple-times/
(memoizing the future after initialisation so that the init function is not called multiple times) however in his solution, he initialises the future like this
Future<String> _future;
this is no longer possible in the current version of dart and I was wondering if there was an equivalent, I have tried using the Late keyword and initializing it to null, neither of which work.
Here is the code currently and how I want it currently:
class _ARState extends State<AR> {
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((_) {
_downloadFiles();
});
}
Future<dynamic> _downloadFiles() async {
// some downloading function that is getting run multiple times ....
}
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: _downloadFiles(),
builder: /// stuff i want built
}
how I want it:
class _ARState extends State<AR> {
Future<dynamic> _future;
@override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((_) {
_downloadFiles();
});
}
Future<dynamic> _downloadFiles() async {
// some downloading function that is getting run multiple times ....
}
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: _future,
builder: /// stuff i want built
}
Upvotes: 0
Views: 6078
Reputation: 90135
One way is to make _future
nullable and to make your asynchronous function idempotent by checking if _future
is null
. If it's null, do work; if it's not null, then just return the existing Future
.
class _ARState extends State<AR> {
Future<dynamic>? _future;
...
Future<dynamic> _downloadFiles() {
Future<dynamic> helper() async {
// Do actual downloading work here.
}
if (_future == null) {
_future = helper();
}
return _future;
}
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: _downloadFiles(),
...
}
}
Upvotes: 4
Reputation: 9754
Try the code below, using late
keyword, but there are other options for that. I think you don't need the addPostFrameCallBack
:
class _ARState extends State<AR> {
late Future<dynamic> _future;
@override
void initState() {
super.initState();
_future = _downloadFiles();
}
Future<dynamic> _downloadFiles() async {
}
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasData || snapshot.data != null) {
// build your widget
}
// progress indicator or something while future is running
return ...;
});
}
Upvotes: 0