Flutter Firebase: обновление данных в Firebase, но автоматическое отображение обновления счетчика на экране не отображается

# #firebase #flutter #asynchronous #google-cloud-firestore #flutter-web

Вопрос:

Я держу счетчик в своей базе огня, который содержит общее количество голосов за картинку. При нажатии кнопки «Голосовать» база данных должна обновить счетчик указанного счетчика на 1, что она и делает. Однако обновление не отображается на экране приложения. Например, если изображение имеет 8 голосов, и кнопка нажата для повышения, на экране по-прежнему будет отображаться 8 голосов, но в базе данных теперь будет 9 голосов. При горячем обновлении значение меняется. Как я могу сделать так, чтобы и то, и другое происходило асинхронно? Я попытался поиграть с ним, и всегда либо он обновляет базу данных, а экран остается неизменным, либо экран меняется, а база данных-нет.

Для функций ниже они ведут себя так, как ожидалось, но только не асинхронно на экране.

Соответствующая функция, которая увеличивает количество подписчиков в базе данных:

 // likedposts is a list of posts that have already been liked and is initalised earlier
// even if I remove the if statement here, the behaviour is the same
void incrementFollowers(int index) async {
  if (!likedposts.contains(posts[index])) { 
  likedposts.add(posts[index]);
  addLikedPost();
  FirebaseFirestore.instance
    .collection('uploads')
    .doc(usernames[index])
    .collection('images')
    .where('caption', isEqualTo: captions[index])
    .get()
    .then((querySnapshot) {
      querySnapshot.docs.forEach((result) async { 
          FirebaseFirestore.instance
          .collection('uploads')
          .doc(usernames[index])
          .collection('images')
          .doc(result.id)
          .update({'upvotes': upvotes[index] 1,});  
          setState(() {
            getUpvotes(index);
          });
      });
    });
   }
  }
 

Функция, отображающая голоса:

 getUpvotes(int index) {
    return RichText(
      text: TextSpan(
          style:
              TextStyle(color: Colors.black, fontSize: 20.0),
          children: <TextSpan>[
          TextSpan(
          text: upvotes[index].toString()   ' upvotes',
          style: TextStyle(color: Colors.blue),
          recognizer: TapGestureRecognizer()
            ..onTap = () {
              print(
                  'This will take to upvoters of the photo');
            }),
      ]));
  }
 

Виджет, который отображает все в моем приложении (чтобы найти, где я вызываю кнопку incrementFollowers, просто нажмите ctrl F для incrementFollowers, и вы найдете его):

 Widget _getPost() {
    
    Size size = MediaQuery.of(context).size;
    if (url!= null) {
    return new ListView.builder(
        itemCount: images.length,
        itemBuilder: (BuildContext context, int userIndex) {
          
          return Container(
            child: Column(
            
            children: <Widget>[
              Container(
                 
                //Includes dp   username   report flag
                margin: EdgeInsets.all(10),
                child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Row(
                      children: <Widget>[
                        Container(
                            margin: EdgeInsets.only(right: 8),
                            child: GestureDetector(
                                onTap: () {
                                Navigator.push(
                                  context, 
                                  MaterialPageRoute(
                                    builder: (context) => UserProfile(usernames[userIndex])
                                    ),
                                  );
                                },
                                child: CircleAvatar(
                                  backgroundImage: displayPic[1],
                                ))),
                        RichText(
                          text: TextSpan(children: <TextSpan>[
                            TextSpan(
                                text: usernames[userIndex],
                                style: TextStyle(
                                    color: Colors.black, fontSize: 15.0),
                                recognizer: TapGestureRecognizer()
                                  ..onTap = () {
                                    Navigator.push(
                                      context, 
                                      MaterialPageRoute(
                                        builder: (context) => UserProfile(usernames[userIndex])
                                      ),
                                    );
                                  })
                          ]),
                        )
                      ],
                    ),
                    
                   IconButton(
                    icon: Image.asset('assets/pictures/ICON_flag.png'),
                    iconSize: 25,
                    onPressed: () {
                      reportUser(userIndex, context);
                
                    },
                  ),
                  ],
                ),
              ),
              Stack(children: <Widget>[
                Container(
                    //the post picture
                    child: GestureDetector(
                      
                      //This is to handle the tagged users raised button
                      onTap: () {
                        if (isVisible == false)
                          setState(() {
                            isVisible = true;
                          });
                        else
                          setState(() {
                            isVisible = false;
                          });
                          
                      },
                    ),
                    height: size.height * 0.5,
                    width: returnWidth(),
                  padding: EdgeInsets.only(
                    left: 16,
                    right: 16,
                    top: 0,
                    bottom: 24,
                  ),
                    // constraints: BoxConstraints(maxHeight: 50),
                   
                    decoration: BoxDecoration(
                      image: DecorationImage(
                         

                          fit: BoxFit.fill, image: NetworkImage(images[userIndex])),
                    )
                    
                    ),
                Positioned(
                  
                    top: 25,
                    left: 50,
                    child: returnTaggedUsers(userIndex),)
              ]),
              Row(
                mainAxisAlignment: returnAlignment(),
                // upvote   downvote   comment   send   save icons
                children: <Widget>[
                  Container(
                    color: upVoted ? Colors.blue : Colors.white,
                      margin: EdgeInsets.only(right: 8),
                      child: IconButton(
                        icon: Image.asset('assets/pictures/ICON_upvote.png'),
                        iconSize: 25,
                        onPressed: () async {
                          setState(() {
                            incrementFollowers(userIndex); 
                            
                          }); 
                          getUpvotes(userIndex);
                        },
                      )

                  ),
                  Container(
                      color: downVoted ? Colors.blue : Colors.white,
                      margin: EdgeInsets.only(right: 8),
                      child: IconButton(
                        icon: Image.asset('assets/pictures/ICON_downvote.png'),
                        iconSize: 25,
                        onPressed: () {
                          setState(() {
                            
                            downVoted = true;
                            upVoted = false;                         
                          });
                        },

                      )),
                  Container(
                      margin: EdgeInsets.only(right: 8),
                      child: IconButton(
                        icon: Image.asset('assets/pictures/ICON_comment.png'),
                        iconSize: 25,
                        onPressed: () {
                         commentPopUp(userIndex, context);
                        },
                      )),
                  Container(
                      margin: EdgeInsets.only(right: 8),
                      child: IconButton(
                        icon: Image.asset('assets/pictures/ICON-send.png'),
                        iconSize: 25,
                        onPressed: () {
                          print(
                              'This will let a user send the post to another user');
                        },
                      )),
                  Container(
                      margin: EdgeInsets.only(right: 8),
                      child: IconButton(
                        icon: Image.asset('assets/pictures/ICON_save.png'),
                        iconSize: 25,
                        onPressed: () {
                          Navigator.push(
                            context, 
                            MaterialPageRoute(
                              builder: (context) => ReportPanel()
                              ),
                            );
                        },
                      )),
                      
                ],
              ),
              Column(
                mainAxisAlignment: returnAlignment(),
                //This column contains username, upload description and total upvotes
                children: <Widget>[
                  Container(
                    
                    //The person who posted along with photo description
                    alignment: returnCommentAlignment(),
                    margin: EdgeInsets.only(left: 10, right: 10),
                    child: RichText(
                        text: TextSpan(
                            style:
                                TextStyle(color: Colors.black, fontSize: 20.0),
                            children: <TextSpan>[
                          TextSpan(
                              text: usernames[userIndex]   ': ',
                              style: TextStyle(color: Colors.blue),
                              recognizer: TapGestureRecognizer()
                                ..onTap = () {
                                  Navigator.push(
                                      context, 
                                      MaterialPageRoute(
                                        builder: (context) => UserProfile(usernames[userIndex])
                                      ),
                                    );
                                }),
                          TextSpan(text: captions[userIndex]),
                        ])),
                  ),
                  Container(
                    //The total upvotes of post
                    alignment: returnCommentAlignment(),
                    margin: EdgeInsets.only(left: 10, right: 10),
                    child: getUpvotes(userIndex), 
                  )
                ],
              ),
              Column(
                mainAxisAlignment: returnAlignment(),
                //This column contains username and comment of commenters
                children: <Widget>[
                  Container(
                    //First comment
                    alignment: returnCommentAlignment(),
                    margin: EdgeInsets.only(left: 10, right: 10),
                    child: RichText(
                        text: TextSpan(
                            style:
                                TextStyle(color: Colors.black, fontSize: 20.0),
                            children: <TextSpan>[
                          TextSpan(
                              text:
                                  'HarperEvans1: ', //will be a username from firebase
                              style: TextStyle(color: Colors.blue),
                              recognizer: TapGestureRecognizer()
                                ..onTap = () {
                                  print(
                                      'This will take to profile of that person');
                                }),
                          TextSpan(text: 'Nice photo!'),
                        ])),
                  ),
                  Container(
                    //Second comment
                    alignment: returnCommentAlignment(),
                    margin: EdgeInsets.only(left: 10, right: 10),
                    child: RichText(
                        text: TextSpan(
                            style:
                                TextStyle(color: Colors.black, fontSize: 20.0),
                            children: <TextSpan>[
                          TextSpan(
                              text:
                                  'trevorwilkinson: ', //will be a username from firebase
                              style: TextStyle(color: Colors.blue),
                              recognizer: TapGestureRecognizer()
                                ..onTap = () {
                                  print(
                                      'This will take to profile of that person');
                                }),
                          TextSpan(
                              text:
                                  'Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda Panda'),
                        ])),
                  ),
                  Container(
                    //view more comments
                    alignment: returnCommentAlignment(),
                    margin: EdgeInsets.only(left: 10, right: 10),
                    child: RichText(
                        text: TextSpan(
                            style:
                                TextStyle(color: Colors.grey, fontSize: 20.0),
                            children: <TextSpan>[
                          TextSpan(
                              text:
                                  'view more comments', //will take to the comments
                              style: TextStyle(color: Colors.grey),
                              recognizer: TapGestureRecognizer()
                                ..onTap = () {
                                  Navigator.push(
                                  context, 
                                  MaterialPageRoute(
                                    builder: (context) => CommentPage(posts[userIndex], usernames[userIndex])
                                    ),
                                  );
                                }),
                        ])),
                  )
                ],
              )
            ],
          ));
        });
    }
  }
 

Спасибо!

Ответ №1:

В настоящее время у вас нет ничего, что могло бы вызвать перестройку с Firebase. Вам нужно вернуть FutureBuilder или StreamBuilder в вашей getUpvotes функции. Это будет получать уведомления об изменениях в облаке и инициировать повторную сборку.

Вот кое-что, с чего вы можете начать. Верните это вместо этого в свой getUpvotes метод и заполните потоковую часть StreamBuilder

 StreamBuilder(
    stream: Firestore.instance.collection...// finish this part to get your snapshot of total upvotes from your collection,
    builder: (context, snapshot) {
         if(snapshot.hasData) {
     return RichText(
      text: TextSpan(
        style: TextStyle(color: Colors.black, fontSize: 20.0),
        children: <TextSpan>[
          TextSpan(
              text: upvotes[index].toString()   ' upvotes',
              style: TextStyle(color: Colors.blue),
              recognizer: TapGestureRecognizer()
                ..onTap = () {
                  print('This will take to upvoters of the photo');
                }),
               ],
             ),
          );
         }
   else {
    // handle no data
   }
 },
);
 

Комментарии:

1. Привет, спасибо за ваш комментарий. Поэтому я попытался сделать то, что вы сказали, однако поведение по-прежнему остается прежним; база данных обновляется, но экран не обновляется до тех пор, пока я не обновлюсь или не перейду на другую страницу и не вернусь на нее. Это то, что я добавил в поток: поток: FirebaseFirestore.экземпляр.коллекция («загрузки»). doc(имена пользователей[индекс]).коллекция («изображения»). снимки (), Но он по-прежнему не обновляет виджет асинхронно. Я сделал что-то не так? Заранее спасибо

2. И только что заметил еще кое-какое странное поведение. Если вы посмотрите на мою функцию incrementFollowers выше, вы увидите строку: .update({'upvotes': upvotes[index] 1,}); . Это означает, что база данных обновляется, но виджет этого не делает. Но если я это сделаю: .update({'upvotes': upvotes[index] ,}); , виджет будет обновляться правильно, а база данных-нет. Не знаю, почему это так

3. Поиграл с твоим решением, и я его получил. Большое спасибо!