firebase里面的for循环监听没有更新

问题描述 投票:0回答:3

在我的应用程序中,我想要来自firebase不同集合的调用数据。首先,我想列出所有项目并获取ID。使用该ID我想从价格收集中检索价格。之后我想从折扣中检索数据。打折我在这里使用循环。在下面的代码中输出即将到来。首先加载清单后,它调用第二个收集价格。任何人都知道解决方案。我想听三个收集。因为如果有任何数据更改我想更新。

    @override
    void initState() {
        super.initState();
        _loadItems();
    }


    Future _loadItems() async {

            int price;
            int discount;

            //calling first collection for getting id and name
            firestore.collection("item").snapshots().listen((itemData)async{

                for(int i=0;i<itemData.documents.length;i++){

                // calling second collection for getting price
                firestore.collection("price").where("id",isEqualTo: itemData.documents[i].data["id"])
                .snapshots().listen((priceData) async{
                        price=priceData.documents[0].data['price'];
                        debugPrint("price showing before loading:"+price.toString());

                                //calling third collection for getting discount
                                firestore.collection("discount")
                                .where("id",isEqualTo: itemData.documents[i].data["id"])
                                .snapshots().listen((discountData) async{
                                    for(int j=0;j<discountData.documents.length;j++){
                                        discount=discountData.documents.data['discount'];
                                    }
                                });

                });

                    setState(() {
                    debugPrint("price showing after loading:"+price.toString());
                    this.documents.add(new CartProduct(
                        name:itemData.documents[i].data["id"],
                        label:itemData.documents[i].data["label"],
                        price:price,
                        discount:discount

                    ));
                    });

                }
        });


    }

目前的输出

    price showing after loading:0
    price showing after loading:0
    price showing after loading:0
    price showing before loading:10.0
    price showing before loading:10.0
    price showing before loading:10.0

预期产出

    price showing before loading:10.0
    price showing before loading:10.0
    price showing before loading:10.0
    price showing after loading:10.0
    price showing after loading:10.0
    price showing after loading:10.0
dart flutter google-cloud-firestore
3个回答
2
投票

我认为你可以使用嵌套的StreamBuilder

Widget getTripleCollectionFromFirebase() {
  return StreamBuilder<QuerySnapshot>(
    stream: Firestore.instance.collection("item").snapshots(),
    builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
      if (snapshot.hasError) return Text("Error: ${snapshot.error}");
      switch (snapshot.connectionState) {
        case ConnectionState.none:
          return Text("No data, yet.");
        case ConnectionState.waiting:
          return Text('Loading...');
        case ConnectionState.active:
        case ConnectionState.done:
          if (snapshot.data == null) {
            return Text("No record");
          } else {
            // Do your staff after first query then call the other collection
            return StreamBuilder<QuerySnapshot>(
              stream: Firestore.instance
                  .collection("price")
                  .where("id", isEqualTo: "fill_it_with_your_code")
                  .snapshots(),
              builder: (BuildContext context,
                  AsyncSnapshot<QuerySnapshot> snapshot) {
                if (snapshot.hasError) return Text("Error: ${snapshot.error}");
                switch (snapshot.connectionState) {
                  case ConnectionState.none:
                    return Text("No data, yet.");
                  case ConnectionState.waiting:
                    return Text('Loading...');
                  case ConnectionState.active:
                  case ConnectionState.done:
                    if (snapshot.data == null) {
                      return Text("No record");
                    } else {
                      // do your staff after second Query
                      return StreamBuilder<QuerySnapshot>(
                        stream: Firestore.instance
                            .collection("discount")
                            .where("id", isEqualTo: "something")
                            .snapshots(),
                        builder: (BuildContext context,
                            AsyncSnapshot<QuerySnapshot> snapshot) {
                          if (snapshot.hasError)
                            return Text("Error: ${snapshot.error}");
                          switch (snapshot.connectionState) {
                            case ConnectionState.none:
                              return Text("No data, yet.");
                            case ConnectionState.waiting:
                              return Text('Loading...');
                            case ConnectionState.active:
                            case ConnectionState.done:
                              if (snapshot.data == null) {
                                return Text("No record");
                              } else {
                                // do your staff after third Query
                                // return the widget which you want to build when all data comes.
                              }
                          }
                        },
                      );
                    }
                }
              },
            );
          }
      }
    },
  );
}


0
投票

这是我的代码。我将逐步解释它,以便您可以将其转换为您的。

buildUserActions返回一个StreamBuilder,StreamBuilder将获取云firestore中的actions集合中的所有文档。当ConnectionStateactive,或done,如果我有数据我将它分配给名为_lastActionDocuments的变量。

  QuerySnapshot _lastActionDocuments;
  Stream<String> streamOfFillActionFields;

  Widget buildUserActions() {
    return StreamBuilder(
      initialData: _lastActionDocuments,
      stream: Firestore.instance.collection('actions').snapshots(),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
            return Center(
              child: CircularProgressIndicator(),
            );
          case ConnectionState.active:
          case ConnectionState.done:
            if (snapshot.hasError)
              return Center(child: Text('Error: ${snapshot.error}'));
            if (!snapshot.hasData) return Text('No data finded!');
            _lastActionDocuments = snapshot.data;
            streamOfFillActionFields = fillActionFields();
            return reallyBuildActions();
        }
      },
    );
  }

然后我有一个Stream功能

  Stream<String> fillActionFields() async* {
    try {
      List<ActionModel> newActionList = [];
      for (DocumentSnapshot actionSnapshot in _lastActionDocuments.documents) {
        var currentAction = ActionModel.fromSnapshot(actionSnapshot);
        // I awaiting to get and fill all data.
        await currentAction.fillAllFields();
        newActionList.add(currentAction);
      }
      actionList = newActionList;
      // what I yield is not important this case 
      yield 'data';
    } catch (e) {
      print(e);
      yield 'nodata';
    }
  }

currentAction.fillAllFields基本上该函数要求firebase获取相关数据以填充我的Action对象中的所有字段。

  Future<void> fillAllFields() async {
    DocumentSnapshot ownerSnapshot = await ownerRef.get();
    owner = UserModel.fromSnapshot(ownerSnapshot);
    DocumentSnapshot routeSnapshot = await routeRef.get();
    route = RouteModel.fromSnapshot(routeSnapshot);
  }

然后我有另一个小部件,它返回一个StreamBuilder。在从引用调用到达所有数据之后,此小部件构建真实UI小部件(buildAllActions)。

  Widget reallyBuildActions() {
    return StreamBuilder(
      stream: streamOfFillActionFields,
      builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
          case ConnectionState.waiting:
            return Center(
              child: CircularProgressIndicator(),
            );
          case ConnectionState.active:
          case ConnectionState.done:
            if (snapshot.data == 'data') {
              return buildAllActions();
            } else {
              return Center(
                child: Column(
                  children: <Widget>[
                    CircularProgressIndicator(),
                    Text('Data Loading...')
                  ],
                ),
              );
            }
        }
      },
    );
  }


0
投票

我有答案使用StreamSubscription并逐个调用。首先,我运行一个循环并检查它是否完成,而不是仅在调用第二个循环之后。它工作正常,但延误。当我使用StreamBuilder它没有完成请求。我不知道为什么会这样。我的代码如下所示。

    StreamSubscription<QuerySnapshot> streamSub1;
    StreamSubscription<QuerySnapshot> streamSub2;
    StreamSubscription<QuerySnapshot> streamSub3;

    var list = new List();


    _loadItems() {

                int price;
                int discount;

                int count =1;

                //calling first collection for getting id and name
            streamSub1= firestore.collection("item").snapshots().listen((itemData)async{


                    for(int i=0;i<itemData.documents.length;i++){
                        list.add(id:itemData.documents[0].data['id'],name:itemData.documents[0].data['id');

                        if(onFavData.documents.length==productCount){
                            debugPrint("loop completed");
                            _loadPrice();
                        }
                    }


            });


    }

    void _loadPrice(){
    streamSub1.cancel();

    int count =1;

    for(int i=0;i<list.length;i++){
        streamSub2= firestore.collection("price").where("id",isEqualTo: itemData.documents[i].data["id"])
                    .snapshots().listen((priceData) async{
                    list[i].price= priceData['price'];
                    if(count==list.length){
                debugPrint("loop completed");
                _loadDiscount();
                }

        });

    }

    }

    _loadDiscount();{
    streamSub2.cancel();

    int count =1;

    for(int i=0;i<list.length;i++){
        streamSub3= firestore.collection("price").where("id",isEqualTo: itemData.documents[i].data["id"])
                    .snapshots().listen((priceData) async{
                    list[i].discount= priceData['price'];
                    if(count==list.length){
                debugPrint("loop completed");

                }

        });

    }

    }
© www.soinside.com 2019 - 2024. All rights reserved.