Issue
This Content is from Stack Overflow. Question asked by Ruder Buster
Im listening to a stream using a bloc. When a user clicks on a chat, the following function is called:
Provider.of<MessageBloc>(context, listen: false).add(LoadMessage(
chat.stingrayId!, chat.chatId, chat.matchedUserImageUrl!,
chat: chat,
stingrayIndex: stingrayIndex,
matchedUserId: chat.matchedUserId!));
which leads to:
void _onLoadMessage(
LoadMessage event,
Emitter<MessageState> emit,
) {
_firestoreRepository
.messages(event.stingrayId, event.messageId)
.listen((messages) {
_firestoreRepository.getUser(event.matchedUserId).listen((matchedUser) {
add(
UpdateMessage(
messages: messages.messages,
matchedUserImageUrls: event.matchedUserImageUrls,
chat: event.chat,
matchedUser: matchedUser,
blocked: messages.blocked,
blockerName: messages.blockerName,
blockerId: messages.blockerId,
stingrayIndex: event.stingrayIndex),
);
});
});
}
and the problem stream it listens to is:
Stream<MessagesWithBlock> messages(String stingrayId, String messageId) {
return FirebaseFirestore.instance
.collection('stingrayMessages')
.doc(messageId)
.snapshots()
.map<MessagesWithBlock>((doc) => MessagesWithBlock.fromSnapshot(doc));
}
For some reason, the error seems to be that users in a chat screen will have their message state changed to a different one when another user sends a message in a different chat. This is a bizarre error, as the loadMessage function is only called once when a chat is loaded, but somehow it seems to be reading a different chat id from a different chat. Any ideas on what is going on?
Thanks!
Solution
This is a common mistake when working with streams – forgetting to close the stream (or cancel a listener) when it’s no longer needed.
In your widget, you need to keep a reference to the listener (presumably some kind of StreamSubscription
) and then once the user has left that page, cancel the listener in the widget’s dispose
function:
late StreamSubscription _listener;
void _onLoadMessage(
LoadMessage event,
Emitter<MessageState> emit,
) {
_listener = _firestoreRepository
.messages(event.stingrayId, event.messageId)
.listen((messages) {
...
});
}
@override
void dispose() {
_listener.cancel();
super.dispose();
}
This Question was asked in StackOverflow by Ruder Buster and Answered by Nick Fisher It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.