UI在渲染前不等待值

时间:2019-07-23 01:47:31

标签: flutter dart

我正在尝试开发一个Flutter Android应用程序,该应用程序将与Cloud Firestore数据库进行通信。我希望它遍历一系列引用中的每个文档,从每个文档中获取一个值,从读取的值中增加一个计数器,然后将其作为文本小部件返回。问题是,尽管我可以从云中读取的值正确打印出计数器,但是读取的值似乎没有反映在UI中。

我尝试使用StreamBuilder和FutureBuilder。我的最后一次尝试是使函数返回Future,并等待读取值,但无济于事。用户界面上反映的就是“未来的实例”。

array (
  0 => 
  array (
    'id' => 'C:\\xampp\\htdocs\\restore_point_backups_fagardesignscom\\files',
    'name' => 'sitebackup_2019_07_19_08_52_37.zip',
    'created' => 1563519157,
  ),
  4 => 
  array (
    'id' => 'C:\\xampp\\htdocs\\restore_point_backups_fagardesignscom\\files',
    'name' => 'sitebackup_2019_07_21_10_12_29.zip',
    'created' => 1563696754,
  ),
  5 => 
  array (
    'id' => 'C:\\xampp\\htdocs\\restore_point_backups_fagardesignscom\\files',
    'name' => 'sitebackup_2019_Jul_21_10_17_58.zip',
    'created' => 1563697083,
  ),
)

“ print(wrapper.value)”调用将打印期望值,但不会在UI中显示。

2 个答案:

答案 0 :(得分:0)

您必须使用仅当ListTile方法完成时才会呈现calculatePrice的FutureBuilder。

在下面的示例中,ListTile在计算进行中包含一个临时的“ ...”,在计算完成时包含一个实际的结果。

Future<double> calculatePrice(DocumentSnapshot pedido) async {
    priceWrapper wrapper = priceWrapper(0);

    for (DocumentReference d in pedido.data['requested_products']) {
      var f = await d.get();
      wrapper.value += f['value'];
    }
    return wrapper.value;
  }

 Widget buildListItem(BuildContext context, DocumentSnapshot document) {
    Future<double> getPrice = calculatePrice(document);

    return FutureBuilder(
      future: getPrice,
      builder: (ctx, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          return ListTile(
            //...
            trailing: Text("${snapshot.data}",
            style: Theme.of(context).textTheme.subtitle,
          );
        }
        else {
          return ListTile(
            //...
            trailing: Text("...",
            style: Theme.of(context).textTheme.subtitle,
          );
        }
      }
    );
  }

现在,关于为什么您的代码似乎可以工作但无法正常工作的问题,所有内容都位于这段代码中

    for (DocumentReference d in pedido.data['requested_products']) {
      d.get().then( (f) {
        wrapper.value += f['value'];
        print(wrapper.value);
      });
    }
    print(wrapper.value);

get方法是一种异步方法,不会中断执行流程。 Insteand将在then完成后注册一个回调(在get中)。由于执行流程没有中断,因此for循环将对所有数据进行迭代。然后,将执行最后一个print语句。 稍后,将调用回调。

由于代码不会被中断,因此您的calculatePrice方法将非常有效地完成拼写,但是结果为priceWrapper(0)wrapper的初始值)。那就是将用来创建您的ListTile的值,以及为什么它似乎不起作用的原因。

使用FutureBuilder可以在完成所有异步工作后管理应用程序的呈现。

答案 1 :(得分:-1)

在您的calculatePrice函数中等待。

for (DocumentReference d in pedido.data['requested_products']) {
  await d.get().then( (f) {
    wrapper.value += f['value'];
    print(wrapper.value);
  });
}

返回的是Future,而不是double

     Widget buildListItem(BuildContext context, DocumentSnapshot document) {
         calculatePrice(document).get().then( (price) { 
             return ListTile(
              trailing: Text("$price"),
              style: Theme.of(context).textTheme.subtitle,
             )
          }
          ).catchError((error, stackTrace) {
            return Text("Error");
            });
     }

希望这会有所帮助