Цикл внутри прослушивания Firebase не обновляется - PullRequest
0 голосов
/ 21 февраля 2019

В моем приложении я хочу вызывать данные из разных коллекций firebase.Сначала я хочу перечислить все предметы и взять идентификатор.Используя этот идентификатор, я хочу получить цену из коллекции цен.После этого я хочу получить данные из скидки.для принятия скидки.Здесь я использую петли.В коде ниже вывод идет.Первый список загрузки, после чего он вызывает вторую цену сбора.Любой знает решение.Я хочу послушать звонки три сборника.Потому что, если какие-либо данные меняются, я хочу обновить.

    @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 голосов
/ 28 февраля 2019

Это мой код.Я объясню это шаг за шагом, чтобы вы могли преобразовать его в свой.

buildUserActions возвращает StreamBuilder, который StreamBuilder принимает все документы, находящиеся в коллекции действий в облачном хранилище.Когда ConnectionState равно active или 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 получение соответствующих данных для заполнения всех полей в моем объекте действия.

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

тогда у меня есть другой виджет, который возвращает StreamBuilder.этот виджет создает реальный виджет пользовательского интерфейса (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 голосов
/ 01 марта 2019

Я получил ответ Используйте 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");

                }

        });

    }

    }
0 голосов
/ 21 февраля 2019

Я думаю, вы можете использовать вложенный StreamBuilder's

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...