Issue
So I have a table in moor which is returning a Future<List<..>>
with that data I am trying to make pie chart
class Stats extends StatefulWidget {
@override
_StatsState createState() => _StatsState();
}
class _StatsState extends State<Stats> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildTaskList(context)
],
);
}
}
FutureBuilder<List<Account>> _buildTaskList(BuildContext context) {
Map<String, double> dataMap = Map();
dataMap.putIfAbsent("SNACKS", () => Provider.of<Amount>(context,listen: false).snack_amount);
dataMap.putIfAbsent("ENTERTAINMENT", () => Provider.of<Amount>(context,listen: false).entertainment_amount);
dataMap.putIfAbsent("STATIONARY", () => Provider.of<Amount>(context,listen: false).stationary_amount);
dataMap.putIfAbsent("OTHERS", () => Provider.of<Amount>(context,listen: false).others_amount);
final dao = Provider.of<AccountDao>(context);
return FutureBuilder(
future: dao.getAllAccounts(),
builder: (context, AsyncSnapshot<List<Account>> snapshot) {
final accounts = snapshot.data ?? List();
Provider.of<Amount>(context,listen: false).add(Calculate(accounts, Type.SNACKS), Calculate(accounts, Type.ENTERTAINMENT),
Calculate(accounts, Type.STATIONARY), Calculate(accounts, Type.OTHERS));
if (accounts == null) {
return Text('No Accounts Yet');
} else {
return PieChart(
dataMap: dataMap,
);
}
},
);
}
double Calculate(List<Account> list, Type type){
double sum=0;
for(int i=0;i<list.length;i++){
if(list[i].type==type){
sum=sum+list[i].amount;
}
}
return sum;
}
Now everytime I am running this I am getting an error
**The following assertion was thrown while dispatching notifications for Amount:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope
value: Instance of ‘Amount’
listening to value
The widget which was currently being built when the offending call was made was: FutureBuilder>
dirty
state: _FutureBuilderState>#37282
When the exception was thrown, this was the stack:
0 Element.markNeedsBuild. (package:flutter/src/widgets/framework.dart:4167:11)
1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4182:6)
2 _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:426:5)
3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:207:21)
4 Amount.add (package:moneymanager/main.dart:55:5)
…
The Amount sending notification was: Instance of ‘Amount’
**
This is the Amount Class
class Amount extends ChangeNotifier {
double snack_amount=0.0;
double entertainment_amount=0.0;
double stationary_amount=0.0;
double others_amount=0.0;
void add(double snack,double entertainment,double stationary, double others){
snack_amount=snack;
entertainment_amount=entertainment;
stationary_amount=stationary;
others_amount=others;
notifyListeners();
}
}
The function to get the Future<List<..>>
“`Future> getAllAccounts()=>select(accounts).get();“
EDIT
I edited my answer as suggested
return FutureBuilder(
future: dao.getAllAccounts(),
builder: (context, AsyncSnapshot<List<Account>> snapshot) {
if(snapshot.connectionState==ConnectionState.done){
final accounts = snapshot.data ?? List();
if (accounts == null) {
return Text('No Accounts Yet');
} else {
Provider.of<Amount>(context,listen: false).add(Calculate(accounts, Type.SNACKS), Calculate(accounts, Type.ENTERTAINMENT),
Calculate(accounts, Type.STATIONARY), Calculate(accounts, Type.OTHERS));
dataMap.putIfAbsent("SNACKS", () => Provider.of<Amount>(context,listen: false).snack_amount);
dataMap.putIfAbsent("ENTERTAINMENT", () => Provider.of<Amount>(context,listen: false).entertainment_amount);
dataMap.putIfAbsent("STATIONARY", () => Provider.of<Amount>(context,listen: false).stationary_amount);
dataMap.putIfAbsent("OTHERS", () => Provider.of<Amount>(context,listen: false).others_amount);
return PieChart(
dataMap: dataMap,
);
}
}else if(snapshot.connectionState==ConnectionState.waiting){
return Container();
}else{
return Container();
}
},
but still the same error
Solution
The following assertion was thrown while dispatching notifications for Amount: setState() or markNeedsBuild() called during build.
This error means that you are calling setState during the build phase
And from you logs it explicitly states
A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase
you can implement ConnectionState.waiting
ConnectionState.done
Answered By – griffins
Answer Checked By – Marilyn (FlutterFixes Volunteer)