Firebase 防止颤振StreamBuilder在ListView中复制数据
我对StreamBuilder和ListView有问题 我的初始构建工作正常,从数据库加载所有节点并将它们添加到ListView: --节点1 --节点2 --节点3 但是,当新节点添加到DB(节点4)时,StreamBuilder会识别更改并将整个节点列表附加到ListView,从而产生重复数据: --节点1 --节点2 --节点3 --节点1 --节点2 --节点3 --节点4Firebase 防止颤振StreamBuilder在ListView中复制数据,firebase,flutter,firebase-realtime-database,stream-builder,Firebase,Flutter,Firebase Realtime Database,Stream Builder,我对StreamBuilder和ListView有问题 我的初始构建工作正常,从数据库加载所有节点并将它们添加到ListView: --节点1 --节点2 --节点3 但是,当新节点添加到DB(节点4)时,StreamBuilder会识别更改并将整个节点列表附加到ListView,从而产生重复数据: --节点1 --节点2 --节点3 --节点1 --节点2 --节点3 --节点4 class _HomeScreenState extends State<HomeScreen> {
class _HomeScreenState extends State<HomeScreen> {
DatabaseReference usersChatsRef =
FirebaseDatabase().reference().child('users-chats');
@override
void initState() {
super.initState();
Stream<List<UsersChats>> getData(User currentUser) async* {
var usersChatsStream = usersChatsRef.child(currentUser.uid).onValue;
var foundChats = List<UsersChats>();
await for (var userChatSnapshot in usersChatsStream) {
Map dictionary = userChatSnapshot.snapshot.value;
if (dictionary != null) {
for (var dictItem in dictionary.entries) {
UsersChats thisChat;
if (dictItem.key != null) {
thisChat = UsersChats.fromMap(dictItem);
} else {
thisChat = UsersChats();
}
foundChats.add(thisChat);
}
}
yield foundChats;
}
}
}
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
appBar: AppBar(),
body: StreamBuilder<List<UsersChats>>(
stream: getData(user),
builder:
(BuildContext context, AsyncSnapshot<List<UsersChats>> snap) {
if (snap.hasError || !snap.hasData)
return Text('Error: ${snap.error}');
switch (snap.connectionState) {
case ConnectionState.waiting:
return Text("Loading...");
default:
return ListView.builder(
itemCount: snap.data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(snap.data[index].id),
subtitle: Text(snap.data[index].lastUpdate),
);
},
);
}
}),
);
}
}
类_homescrenstate扩展状态{
数据库引用usersChatsRef=
FirebaseDatabase().reference().child('users-chats');
@凌驾
void initState(){
super.initState();
Stream getData(用户当前用户)异步*{
var userschatstream=usersChatsRef.child(currentUser.uid).onValue;
var foundChats=List();
等待(usersChatsStream中的var userchatsnashot){
Map dictionary=userChatSnapshot.snapshot.value;
如果(字典!=null){
for(dictionary.entries中的变量dictItem){
用户聊天;
如果(dictItem.key!=null){
thisChat=UsersChats.fromMap(dictItem);
}否则{
thisChat=UsersChats();
}
foundChats.add(thisChat);
}
}
产量和产量;
}
}
}
@凌驾
小部件构建(构建上下文){
最终用户=提供者(上下文);
返回脚手架(
appBar:appBar(),
正文:StreamBuilder(
流:getData(用户),
建设者:
(BuildContext上下文,异步快照快照){
if(snap.hasrerror | | |!snap.hasData)
返回文本('Error:${snap.Error}');
开关(快速连接状态){
案例连接状态。正在等待:
返回文本(“加载…”);
违约:
返回ListView.builder(
itemCount:snap.data.length,
itemBuilder:(上下文,索引){
返回列表块(
标题:文本(snap.data[index].id),
字幕:文本(snap.data[index].lastUpdate),
);
},
);
}
}),
);
}
}
classuserschats{
字符串id;
字符串更新;
用户沙茨(
{this.id,
此文件为.lastUpdate});
工厂用户schats.fromMap(映射条目数据){
返回UsersChats(
id:data.key???“”,
lastUpdate:data.value['lastUpdate']??'';
}
}
我在build方法之外引用流,因为我需要在流上执行多个异步函数(如本线程中所讨论的)
任何帮助都将不胜感激 发布工作代码。再次感谢雷米的提示!!希望这段代码对其他人有帮助
class _HomeScreenState extends State<HomeScreen> {
DatabaseReference usersChatsRef =
FirebaseDatabase().reference().child('users-chats');
List<UsersChats> myChats = [];
StreamSubscription _streamSubscription;
@override
void initState() {
super.initState();
_streamSubscription = getData().listen((data) {
setState(() {
myChats = data;
});
});
}
@override
void dispose() {
_streamSubscription?.cancel(); // don't forget to close subscription
super.dispose();
}
Stream<List<UsersChats>> getData() async* {
var usersChatsStream = usersChatsRef.child('userId').onValue;
var foundChats = List<UsersChats>();
await for (var userChatSnapshot in usersChatsStream) {
foundChats.clear();
Map dictionary = userChatSnapshot.snapshot.value;
if (dictionary != null) {
for (var dictItem in dictionary.entries) {
UsersChats thisChat;
if (dictItem.key != null) {
thisChat = UsersChats.fromMap(dictItem);
} else {
thisChat = UsersChats();
}
foundChats.add(thisChat);
}
}
yield foundChats;
}
}
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
itemCount: myChats.length,
itemBuilder: (context, index) {
title: Text(myChats[index].id),
subtitle: Text(myChats[index].lastUpdate),
onTap: () {
Navigator.pushNamed(context, MessagesScreen.id);
},
);
},
),
);
}
}
class\u homescrenstate扩展状态{
数据库引用usersChatsRef=
FirebaseDatabase().reference().child('users-chats');
列出mychat=[];
StreamSubscription\u StreamSubscription;
@凌驾
void initState(){
super.initState();
_streamSubscription=getData()。侦听((数据){
设置状态(){
myChats=数据;
});
});
}
@凌驾
无效处置(){
_streamSubscription?.cancel();//不要忘记关闭订阅
super.dispose();
}
流getData()异步*{
var userschatstream=usersChatsRef.child('userId').onValue;
var foundChats=List();
等待(usersChatsStream中的var userchatsnashot){
foundChats.clear();
Map dictionary=userChatSnapshot.snapshot.value;
如果(字典!=null){
for(dictionary.entries中的变量dictItem){
用户聊天;
如果(dictItem.key!=null){
thisChat=UsersChats.fromMap(dictItem);
}否则{
thisChat=UsersChats();
}
foundChats.add(thisChat);
}
}
产量和产量;
}
}
@凌驾
小部件构建(构建上下文){
最终用户=提供者(上下文);
返回脚手架(
appBar:appBar(),
正文:ListView.builder(
itemCount:myChats.length,
itemBuilder:(上下文,索引){
标题:文本(myChats[index].id),
字幕:文本(myChats[index].lastUpdate),
onTap:(){
Navigator.pushNamed(上下文,MessagesScreen.id);
},
);
},
),
);
}
}
听起来像是usersChatsRef.child(currentUser.uid)。onValue
会在每次更改时发出整个列表,而不是只推送差异。这意味着您不必“添加”到foundChat
,只需删除之前的列表即可。感谢您的快速回复!您知道如何修改getData
函数吗?一直在尝试不同的方法,但到目前为止没有任何运气。请尝试清除“等待”的第一行中的foundChats
!!做到了,非常感谢!!!剩下的唯一问题是,当我使用Navigator.push
并导航到主屏幕,ListView的数据就会消失。可能需要StreamSubscription(如您在此处概述的:)?我正在努力添加这个,如果成功,我会发布我的结果。
class _HomeScreenState extends State<HomeScreen> {
DatabaseReference usersChatsRef =
FirebaseDatabase().reference().child('users-chats');
List<UsersChats> myChats = [];
StreamSubscription _streamSubscription;
@override
void initState() {
super.initState();
_streamSubscription = getData().listen((data) {
setState(() {
myChats = data;
});
});
}
@override
void dispose() {
_streamSubscription?.cancel(); // don't forget to close subscription
super.dispose();
}
Stream<List<UsersChats>> getData() async* {
var usersChatsStream = usersChatsRef.child('userId').onValue;
var foundChats = List<UsersChats>();
await for (var userChatSnapshot in usersChatsStream) {
foundChats.clear();
Map dictionary = userChatSnapshot.snapshot.value;
if (dictionary != null) {
for (var dictItem in dictionary.entries) {
UsersChats thisChat;
if (dictItem.key != null) {
thisChat = UsersChats.fromMap(dictItem);
} else {
thisChat = UsersChats();
}
foundChats.add(thisChat);
}
}
yield foundChats;
}
}
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
appBar: AppBar(),
body: ListView.builder(
itemCount: myChats.length,
itemBuilder: (context, index) {
title: Text(myChats[index].id),
subtitle: Text(myChats[index].lastUpdate),
onTap: () {
Navigator.pushNamed(context, MessagesScreen.id);
},
);
},
),
);
}
}