FutureBuilder 与 Notifylistener 冲突

Posted

技术标签:

【中文标题】FutureBuilder 与 Notifylistener 冲突【英文标题】:FutureBuilder conflict with Notifylistener 【发布时间】:2021-10-23 17:08:15 【问题描述】:

我的提供程序文件中有一个这样的方法来更新来自服务器的项目列表:

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);
     
    
  

在我的主屏幕中,我将该列表包装到 FutureBuilder 中,它可以正常工作并返回一个列表:


 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),
          ),
        ),

但是当我在我的方法中添加 notifylistener() 时,我未来的构建器列表停留在等待状态并且不会更新列表这里出了什么问题

【问题讨论】:

【参考方案1】:

@nvoigt

这是我的小部件,我已从构建方法中删除了这些提供程序


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]),
                ),
              );
            ,
          ),
        ),
      ],
    );
  

如您所见,我的构建方法中没有任何内容,并且我使用 Consumer 来避免此循环,但仍然构建方法正在重建,您能用代码 sn-ps 解释一下吗?我很感激

【讨论】:

"future: Provider.of(context, listen: false).getServerMeals()" 这行是你的问题。每次构建都会调用它,这意味着您的 Future 将在每次构建调用时重新开始。您需要在构建方法的 outside 某处有类似 "myVariable = Provider.of(context, listen: false).getServerMeals()" 的行,并且您的构建方法应该具有“未来: myVariable," 代替。 @nvoigt 我是新手对不起,如果它真的是基本问题,所以如果我把这行 myVariable = Provider.of&lt;EatenMeals&gt;(context, listen: false).getServerMeals() 放在 initState 或 didChangedepndencies 我应该如何在构建方法中获得 myVariable 值?? 例如,通过使其成为您所在州的成员变量。这是与 FutureBuilder 一起使用的 Future 的一个小而完整的示例:***.com/questions/63017280/…【参考方案2】:

这是因为调用notifyListeners 将重建build 方法(您调用Provider.of... 的那个方法),这将创建一个循环。(build 方法调用未来,notifyListener 将重建build 方法,这个过程会一直持续下去)。

为防止这种情况,请为 of 方法提供另一个参数:listen: false

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

这将阻止build 方法重建。

【讨论】:

这是正确的,但解决方案是胶带“解决方案”。很多其他的事情都可以触发build方法,build方法需要固定,而不是provider。 连接状态仍然卡在等待中 @nvoigt 在我将 Future 移到构建方法之外后,您会告诉我我提供给未来构建器的“未来”参数吗?例如,当有人更改日期时,我想更新该列表,当数据发生更改时,我应该如何触发未来的构建器重建? 您在小部件状态中使用了 Future 类型的变量。例如:***.com/questions/63017280/… @nvoigt 请在下面阅读我的问题,我真的很困惑,我写了答案:【参考方案3】:

问题是你在你的构建方法中创造你的未来。

这意味着在每次构建时,您再次创造这个未来。

这是您程序中的一个小麻烦和错误,直到您还添加未来本身触发重建,这意味着它将运行,触发重建,重建将等待一个 new 未来,它将运行,触发重建,再次创建一个 new 未来......你明白了。这是一个无限循环的运行未来,只是为了重建和运行它。

你必须创建你的未来在构建方法之外。 build 方法可以被多次触发。仅在您的构建方法中引用 Future 类型变量,并在另一个方法中分配该变量,可能是 init 或当有人单击按钮时在某些 setState 调用中。

【讨论】:

以上是关于FutureBuilder 与 Notifylistener 冲突的主要内容,如果未能解决你的问题,请参考以下文章

FutureBuilder 与 Streambuilder

FutureBuilder 与 Notifylistener 冲突

6-3 异步:Future与FutureBuilder实用技巧

FlutterFutureBuilder 异步编程 ( FutureBuilder 构造方法 | AsyncSnapshot 异步计算 )

FutureBuilder 显示加载指示器,尽管结果已缓存

Flutter FutureBuilder 在另一个 FutureBuilder 中,取自 JSON 字符串数组