Firebase内的for循环监听未更新

时间:2019-02-21 11:49:52

标签: dart flutter google-cloud-firestore

在我的应用程序中,我希望从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

3 个答案:

答案 0 :(得分: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.
                              }
                          }
                        },
                      );
                    }
                }
              },
            );
          }
      }
    },
  );
}

答案 1 :(得分:0)

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

buildUserActions返回一个StreamBuilder,StreamBuilder会获取Cloud Firestore的动作集合中的所有文档。当ConnectionStateactivedone(如果我有数据)时,将其分配给名为_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获取相关数据以填充我的操作对象中的所有字段。

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

答案 2 :(得分: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");

                }

        });

    }

    }