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
}
Thanks for any help!
CodePudding user response:
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) {
return _future;
}
return helper();
}
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: _downloadFiles(),
...
}
}
CodePudding user response:
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 ...;
});
}
