Flutter Firebase:Firebase 中的数据更新,但不会自动在屏幕上显示计数器更新
Flutter Firebase: data updating in Firebase, but not showing the counter update on the screen automatically
我在我的 Firebase 中有一个计数器,它保存一张图片的总投票数。当按下投票按钮时,数据库应该将指定计数器的计数器更新为 1,它确实这样做了。但是,它不会在应用程序屏幕上显示更新。例如,如果一个图像有 8 个赞成票,并且按下按钮进行赞成票,它仍然会在屏幕上显示 8 个赞成票,但在数据库中它现在将是 9 个赞成票。当我热刷新时,值会发生变化。我怎样才能让这两件事异步发生?我试着玩弄它,它总是更新数据库而屏幕保持不变,或者屏幕改变而数据库没有。
对于以下函数,它们的行为符合预期,但在屏幕上不是异步的。
增加数据库中followers的相关函数:
// 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 按钮的位置,只需对 incrementFollowers 执行 ctrl+F 即可找到):
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])
),
);
}),
])),
)
],
)
],
));
});
}
}
谢谢!
目前您没有任何东西可以触发 Firebase 的重建。您需要在 getUpvotes
函数中 return 一个 FutureBuilder
或 StreamBuilder
。这将收到云中更改的通知并触发重新构建。
这里有一些可以帮助您入门的东西。 Return 改为在您的 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
}
},
);
我在我的 Firebase 中有一个计数器,它保存一张图片的总投票数。当按下投票按钮时,数据库应该将指定计数器的计数器更新为 1,它确实这样做了。但是,它不会在应用程序屏幕上显示更新。例如,如果一个图像有 8 个赞成票,并且按下按钮进行赞成票,它仍然会在屏幕上显示 8 个赞成票,但在数据库中它现在将是 9 个赞成票。当我热刷新时,值会发生变化。我怎样才能让这两件事异步发生?我试着玩弄它,它总是更新数据库而屏幕保持不变,或者屏幕改变而数据库没有。
对于以下函数,它们的行为符合预期,但在屏幕上不是异步的。
增加数据库中followers的相关函数:
// 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 按钮的位置,只需对 incrementFollowers 执行 ctrl+F 即可找到):
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])
),
);
}),
])),
)
],
)
],
));
});
}
}
谢谢!
目前您没有任何东西可以触发 Firebase 的重建。您需要在 getUpvotes
函数中 return 一个 FutureBuilder
或 StreamBuilder
。这将收到云中更改的通知并触发重新构建。
这里有一些可以帮助您入门的东西。 Return 改为在您的 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
}
},
);