How to solve this error "setState() or markNeedsBuild() called during build."?

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)

Leave a Reply

Your email address will not be published. Required fields are marked *