我在StreamBuilder和ListView上遇到问题。
我的初始构建按预期工作,从数据库中加载所有节点并将其添加到ListView:
-节点1 -节点2 -节点3
但是,当将新节点添加到数据库(节点4)时,StreamBuilder会识别出更改并将整个节点列表追加到ListView,从而产生重复数据:
-节点1 -节点2 -节点3 -节点1 -节点2 -节点3 -节点4
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),
);
},
);
}
}),
);
}
}
class UsersChats {
String id;
String lastUpdate;
UsersChats(
{this.id,
this.lastUpdate});
factory UsersChats.fromMap(MapEntry<dynamic, dynamic> data) {
return UsersChats(
id: data.key ?? '',
lastUpdate: data.value['lastUpdate'] ?? '');
}
}
我在build方法之外引用该流,因为我需要对该流执行多个异步功能(如本线程How do I join data from two Firestore collections in Flutter?中所述)。
任何帮助将不胜感激!
答案 0 :(得分:1)
发布工作代码。再次感谢Remi的提示!!希望这段代码对其他人有帮助!
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);
},
);
},
),
);
}
}