Flutter UI在呈现之前不等待值

Flutter UI在呈现之前不等待值,flutter,dart,Flutter,Dart,我正在尝试开发一款Fatterandroid应用程序,它将与云Firestore数据库进行通信。我希望它遍历一系列引用中的每个文档,从每个文档中获取一个值,从读取的值中增加一个计数器,并将其作为文本小部件返回。问题是,读取的值似乎没有反映在UI中,尽管我可以从云中读取的值正确打印出计数器 我尝试使用StreamBuilder和FutureBuilder。我最后一次尝试是让我的函数返回一个Future,并等待读取该值,但没有成功。UI上反映的只是未来的实例 Future<double>

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

我尝试使用StreamBuilder和FutureBuilder。我最后一次尝试是让我的函数返回一个Future,并等待读取该值,但没有成功。UI上反映的只是未来的实例

Future<double> calculatePrice(DocumentSnapshot pedido) async{

    priceWrapper wrapper = priceWrapper(0);

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

 Widget buildListItem(BuildContext context, DocumentSnapshot document) {
    return ListTile(
      //...
      trailing: Text("${calculatePrice(document)}",
        style: Theme.of(context).textTheme.subtitle,
      ),
    );
  }

@override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: CustomDrawer(
        context: context,
      ),
      appBar: AppBar(
        title: Text("Requests"),
      ),
      body: Container(
        //...
        child: StreamBuilder(
          stream: Firestore.instance.collection("currentRequests").snapshots(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) {
              if (snapshot.hasError) {
                print("SNAPSHOT ERROR: ${snapshot.error}");
              }
              return LinearProgressIndicator();
            }
            return ListView.separated(
              itemCount: snapshot.data.documents.length,
              itemBuilder: (context, index) {
                    return buildListItem(context, snapshot.data.documents[index]);
              },
            );
          },

        ),
      ),
    );
  }

printwrapper.value调用打印期望值,但该值不会显示在UI中。

在calculatePrice函数中放入等待

for (DocumentReference d in pedido.data['requested_products']) {
  await d.get().then( (f) {
    wrapper.value += f['value'];
    print(wrapper.value);
  });
}
同样,被归还的是一个未来,而不是一个双倍的未来

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

希望这对您有所帮助

您必须使用FutureBuilder,它仅在calculatePrice方法完成后才会呈现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,
          );
        }
      }
    );
  }
在下面的示例中,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,
          );
        }
      }
    );
  }
get方法是异步的,不会中断执行流。INSTEAN将在中注册回调,然后在get完成时调用该回调。由于执行流没有中断,for循环将迭代所有数据。然后,将执行最后一条print语句。 稍后,将调用回调

由于代码没有中断,您的calculatePrice方法将有效地非常快地完成,但结果是priceWrapper0是wrapper的初始值。这就是将用于创建ListTile的值,以及它似乎不起作用的原因


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

您需要一个FutureBuilder作为后续属性的小部件使用异步请求强制UIYes,我的问题实际上是由于FutureBuilder的使用不正确。谢谢你的意见!