Problem My FutureBuilder waits when app first runs but doesn't wait when app updates.
When my app finishes loading and I change to a different ToggleButton, the FutureBuilder starts to rerun immediately instead of waiting for getData() and it fully completes before getData() is finished and then when getData() is finally finished, FutureBuilder runs again.
This problem does not happen when the app first runs. When the app first runs, the FutureBuilder waits for getData() to complete before running.
I need FutureBuilder to wait for getData() to finish when a different button is pressed just like it does when the app first starts up.
Note: I removed as much unnecessary code as I could for readability. I can add more code if it will help.
Code:
class PriceScreenState extends State<PriceScreen> {
String selectedCurrency = 'USD';
String selectedGraphType = "1D";
var isSelectedGraph = <bool>[true, false, false, false, false, false];
getData() async {
isWaiting = true;
try {
Map graphData = await GraphData().getGraphData(
selectedCurrency: selectedCurrency,
selectedGraphType: selectedGraphType);
isWaiting = false;
setState(() {
graphValues = graphData;
});
} catch (e) {
print(e);
}
}
@override
void initState() {
super.initState();
futureData = getData();
}
@override
Widget build(BuildContext context) {
...(other code)...
ToggleButtons( ****************TOGGLEBUTTONS***********
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text('1D'),
),
...(more Buttons)...
],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0;
buttonIndex < isSelectedGraph.length;
buttonIndex++) {
if (buttonIndex == index) {
isSelectedGraph[buttonIndex] = true;
selectedGraphType = graphType[buttonIndex];
} else {
isSelectedGraph[buttonIndex] = false;
}
}
});
getData();
},
isSelected: isSelectedGraph,
),
Expanded(
child: FutureBuilder( *************FUTUREBUILDER*********
future: futureData,
builder: (context, snapshot) {
if (graphValues.isEmpty) {
return new Container();
} else {
return Graph(graphValues);
}
}),
)
As you are using a FutureBuilder
you don't need to call setState
anymore. Here is a possible rework of your code:
Future<Map> futureData;
Future<Map> getData() async {
try {
Map graphData = await GraphData().getGraphData(
selectedCurrency: selectedCurrency,
selectedGraphType: selectedGraphType,
);
return graphData;
} catch (e) {
throw Exception(e);
}
}
@override
void initState() {
super.initState();
futureData = getData();
}
@override
Widget build(BuildContext context) {
// Only coding the FutureBuilder for the example
return FutureBuilder<Map>(
future: futureData,
builder: (context, snapshot) {
// Future is still loading
if (!snapshot.hasData)
return CircularProgressIndicator();
else if (snapshot.data.isEmpty)
return Container();
else
return Graph(snapshot.data);
},
);
}
For your FutureBuilder
to work correctly you need to return a value in your getData
and use the snapshot
variable.