1

I have a method like this in my provider file to update a list of items from server :

Future<void> getServerMeals(String userName, String date) async {
    final QueryBuilder<ParseObject> parseQuery =
        QueryBuilder<ParseObject>(ParseObject('UsersEaten'));

    parseQuery
      ..whereContains('eatenBy', userName)
      ..whereEqualTo('eatenDate', date);

    final ParseResponse apiResponse = await parseQuery.query();

    if (apiResponse.success && apiResponse.results != null) {
      List<dynamic>? apiRes = apiResponse.results;

      List<dynamic> newMeals = apiRes!
          .map((e) => EatenItem(
                id: e['objectId'],
                eatenCal: e['eatenCal'],
                eatenTitle: e['eatenTitle'],
                eatenImageUrl: e['eatenImg'],
                userId: e['objectId'],
              ))
          .toList();
      _eatenMeals = newMeals;
      print(apiResponse.results);
     
    }
  }

and in my main screen I've wrapped that list into the FutureBuilder it works fine and return a list:


 Container(
          height: MediaQuery.of(context).size.height * 0.6,
          margin: EdgeInsets.only(left: 30, right: 30),
          child: FutureBuilder(
            builder: (ctx, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return Center(
                  child: CircularProgressIndicator(),
                );
              }

              return ListView.builder(
                itemCount: mealsList.eatenMeals.length,
                itemBuilder: (ctx, index) =>
                    DailyEaten(mealsList.eatenMeals[index]),
              );
            },
            future: Provider.of<EatenMeals>(context)
                .getServerMeals(currentUser.username, now),
          ),
        ),

but when I've added notifylistener() in my method my future builder list stuck on waiting state and won't update list what's wrong here

Behnam
  • 329
  • 5
  • 15

3 Answers3

2

The problem is that you are creating your future in your build method.

That means on every build, you create this future again.

That is a minor nuisance and a bug in your program, until you also add that the future itself triggers a rebuild, which means it will run, trigger a rebuild, the rebuild will wait for a new future, that will run, trigger a rebuild, create yet again a new future... you get it. It's an endless circle of running a future only to rebuild and run it again.

You have to create your Future outside of the build method. The build method can be triggered many times. Only reference a Future<> type variable in your build method and assign that variable in another method, maybe init or in some setState call when someone clicks a button.

nvoigt
  • 75,013
  • 26
  • 93
  • 142
2

It is because calling notifyListeners will rebuild the build method(The one from which you have called Provider.of...), which will create a loop.(The build method call the future and notifyListener will rebuild the build method, and this process continues for ever).

To prevent this, provide another argument to the of method: listen: false

Provider.of<EatenMeals>(context, listen: false).getServerMeals(currentUser.username, now);

This will prevent the build method to rebuild.

Ehsan Askari
  • 843
  • 7
  • 19
  • This is correct, but the solution is a duct tape "solution". Many other things can trigger the build method, the build method needs to be fixed, not the provider. – nvoigt Aug 23 '21 at 12:26
  • 1
    connection state still stuck on waiting – Behnam Aug 23 '21 at 16:02
  • @nvoigt would you tell me after I move my Future outside of build method what I provide as 'future' argument to future builder? for example when someone change date I wanna update that list how should I trig that future builder to rebuild when data has changed? – Behnam Aug 23 '21 at 18:47
  • You use a variable of type Future in your widget state. See for example this: https://stackoverflow.com/questions/63017280/what-is-a-future-and-how-do-i-use-it – nvoigt Aug 23 '21 at 18:57
  • @nvoigt please read my problem below , I'm really getting confused , I wrote as answer : – Behnam Aug 24 '21 at 12:19
0

@nvoigt

here is my widget and I've removed those Providers from build method


class TimelineWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
  
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [

        Container(
          child: FutureBuilder(
           future: Provider.of<EatenMeals>(context, listen: false).getServerMeals(),
            builder: (ctx, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return Center(
                  child: CircularProgressIndicator(),
                );
              }

              return Consumer<EatenMeals>(
                builder: (ctx, mealsList, child) => ListView.builder(
                  itemCount: mealsList.eatenMeals.length,
                  itemBuilder: (ctx, index) =>
                      DailyEaten(mealsList.eatenMeals[index]),
                ),
              );
            },
          ),
        ),
      ],
    );
  }

as you can see there is nothing in my build method , and I've used Consumer to avoid this loop , but still build method getting rebuild , would you explain with code snippets I appreciate it

Behnam
  • 329
  • 5
  • 15
  • "future: Provider.of(context, listen: false).getServerMeals()" this line is your problem. It will be called with every build, which means your Future will start anew with every call to build. You need to have a line like "myVariable = Provider.of(context, listen: false).getServerMeals()" somewhere *outside* of your build method and your build method should have a "future: myVariable," instead. – nvoigt Aug 24 '21 at 12:21
  • @nvoigt I'm newbie sorry if its really basic question , so if I put this line `myVariable = Provider.of(context, listen: false).getServerMeals() ` in initState or didChangedepndencies how should I get `myVariable` value in build method?? – Behnam Aug 24 '21 at 12:29
  • By making it a member variable of your state for example. This is a small but complete example of a Future in use with a FutureBuilder: https://stackoverflow.com/questions/63017280/what-is-a-future-and-how-do-i-use-it – nvoigt Aug 24 '21 at 12:33