更新2
经过大量调试,我意识到在messages子集合中创建消息时会发生错误。在我写了聊天集合的子级Messages子集合之后,无论查询中有什么内容,它都会读取所有文档。我尝试了多种类型的查询,这些查询从一开始就可以使用,但是当我写入messages子集合时,它将读取所有文档,甚至包括我已经阅读的文档。
当我写到messages子集合时,我将批处理行注释掉,而仅在chats集合中显示最近的消息。再一次,这仅发生在发送消息的用户,现在是接收消息的用户。接收消息的用户将获得文档,当我重新进入聊天时,它不会调用所有文档。但是编写该msg并发送该消息的用户,以及该用户重新进入聊天室时,将读取所有文档,除非我不写到messages子集合,而只是更新chats集合。
代码:
Future createChat({Chat chat, isCreating = false}) async => await Services().crud.batch(
onBatch: (batch) {
if (isCreating) {
batch.set(
APIs().chats.collection.doc(chat.chatID).collection(Constants.messages).doc(),
chat.recentMessage.map(),
);
batch.set(
APIs().chats.collection.doc(chat.chatID),
chat.map(),
);
} else {
batch.set(
APIs().chats.collection.doc(chat.chatID).collection(Constants.messages).doc(),
chat.recentMessage.map(),
);
batch.update(
APIs().chats.collection.doc(chat.chatID),
<String, dynamic>{
'recentMessage': chat.recentMessage.map(),
'updatedAt': chat.updatedAt,
},
);
}
},
onSuccess: () => Funcs.log('Success'),
onFailure: (e) => Funcs.log(e),
);
我遇到了一个奇怪的问题,在我的聊天应用程序中,我有两个用户正在交谈,而在打开聊天页面时,它可以完美运行,实时收听传入消息,向上滚动以获取较旧的消息等。当我最初向用户发送消息时返回,然后返回到聊天列表页面,然后返回到Firestore读取并显示集合中的所有消息的聊天。但是在其他用户方面,当他收到一条消息后,没有响应就回去,然后又回到聊天室,这是正常的,没有任何奇怪的事情发生,直到我先发送一条消息然后回去然后再进入,然后其他用户集合中的所有消息。我还注意到,当用户接收到一条消息时,聊天流被调用一次,但是当用户发送一条消息时,则聊天呼叫倍增...
我设置的方式是,我正在侦听收到最新消息后添加的最新文档,如果没有以前的消息,则仅侦听传入的消息。当用户发送消息并发送后,然后通过Cloud Functions发送通知。 didComplete: true
是Cloud Functions的回报。 MOD
是修改的缩写,在聊天流中有修改的聊天记录。
再次说明一下,问题发生在用户发送消息,关闭聊天页面,再次打开聊天页面,然后即使有查询在哪里阅读时,集合中的所有文档也被读取在上一次阅读文档之后...因此,当我应该只阅读新文档时,它对所有先前文档的阅读方式对我来说甚至都没有意义。
代码-messages_list.dart
// ignore: cancel_subscriptions
StreamSubscription _streamSubscription;
bool _isFetching = false;
bool _didFetch = false;
@override
void initState() {
Funcs.log(widget.chat.messages.map((e) => e.msg).toList());
widget.chat.messages.isEmpty
? this._moreMessages().then((value) {
this._initMessages();
widget.scrollToBtm();
})
: this._initMessages();
super.initState();
}
@override
void dispose() {
this._streamSubscription.cancel();
super.dispose();
}
_initMessages() {
Funcs.log('Init Live Messages...');
var q;
widget.chat.messages.isEmpty
? q = APIs().chats.collection.doc(widget.chat.chatID).collection('messages').orderBy('createdAt', descending: false)
: q = APIs()
.chats
.collection
.doc(widget.chat.chatID)
.collection('messages')
.orderBy('createdAt', descending: false)
.startAfterDocument(widget.chat.messages.last.ds);
this._streamSubscription = q.snapshots().listen((event) {
event.docChanges.forEach((element) {
Message m = Message.model(ds: element.doc, id: element.doc.id, map: element.doc.data());
Funcs.log('READ ${m.msg}');
if (mounted)
setState(() {
if (element.type == DocumentChangeType.added) {
widget.chat.messages.add(m);
widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
}
if (element.type == DocumentChangeType.modified) {
int index = widget.chat.messages.indexOf(m);
if (index >= 0) {
widget.chat.messages[index] = m;
widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
}
}
if (element.type == DocumentChangeType.removed) {
widget.chat.messages.remove(m);
widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
}
});
Funcs.log(widget.chat.messages.map((e) => e.msg).toList());
});
});
}
Future _moreMessages() async {
if (!this._isFetching && !this._didFetch) {
setState(() => this._isFetching = true);
List<Message> messages;
if (widget.chat.messages.isEmpty) {
Funcs.log('Getting Messages...');
messages = await APIs().chats.initMessages(chat: widget.chat);
Funcs.log(messages.map((e) => e.msg).toList());
} else {
Funcs.log('Getting More Messages...');
messages = await APIs().chats.moreMessages(chat: widget.chat);
Funcs.log(messages.map((e) => e.msg).toList());
}
if (messages != null) {
int oldCount = widget.chat.messages.length;
widget.chat.messages.addAll(messages);
widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
int newCount = widget.chat.messages.length;
if (oldCount != newCount) {
} else {
this._didFetch = true;
}
setState(() => this._isFetching = false);
}
Funcs.log('Getting Messages Complete.');
}
}
chat_page.dart
Chat _chat;
@override
void initState() {
this._chat = widget.chat;
super.initState();
}
Widget _column() => Column(
children: <Widget>[
this._chat != null
? MessagesList(
controller: this._scrollController,
isReversed: false,
chat: this._chat,
scrollToBtm: this._scrollToBtm,
)
: Expanded(
child: Container(),
),
Container(
color: Colors.black,
height: 1.0,
),
Container(
height: 45.0,
decoration: BoxDecoration(),
margin: EdgeInsets.only(left: 15.0, right: 15.0, bottom: 15.0),
child: Column(
children: <Widget>[
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.only(right: 15.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: TextField(
controller: this._msgTEC,
focusNode: this._msgFN,
decoration: InputDecoration.collapsed(
hintText: 'Enter Message',
fillColor: Colors.white,
),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.send,
textCapitalization: TextCapitalization.sentences,
onSubmitted: (s) => this._sendMessage(
auth: auth,
main: main,
type: 'Text',
msg: s,
),
),
),
),
),
GestureDetector(
child: Icon(Icons.send),
onTap: () => this._sendMessage(
auth: auth,
main: main,
type: 'Text',
msg: this._msgTEC.text,
),
),
],
),
),
],
),
),
],
);
_scrollToBtm() {
if (this._scrollController.hasClients)
this._scrollController.animateTo(this._scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 500), curve: Curves.easeOut);
}
Future _sendMessage({AuthProvider auth, MainProvider main, String type, String msg}) async {
if (msg.trim().isEmpty) return;
var now = Services().values.now();
Chat chat = Chat(
chatID: this._chat == null ? APIs().chats.collection.doc().id : this._chat.chatID,
users: [widget.user.userID, auth.user.userID],
recentMessage: Message(
owner: APIs().users.collection.doc(auth.user.userID),
type: type,
msg: msg,
createdAt: now,
),
createdAt: now,
updatedAt: now,
);
await main
.createChat(
chat: chat,
isCreating: this._chat == null,
)
.then((value) async {
if (mounted)
setState(() {
if (this._chat == null) this._chat = chat;
this._msgTEC.text = '';
});
this._scrollToBtm();
Map<dynamic, dynamic> results = await Services().cloudFunction.notifyUserInChat(data: <String, dynamic>{
'toUserID': widget.user.userID,
'selfie': widget.user.profile.selfie,
'name': widget.user.profile.name,
'chatID': this._chat.chatID,
'msg': msg,
'tokens': widget.user.settings.tokens.fcm,
});
Funcs.log(results);
});
}
main_provider.dart-始终作为提供商窗口小部件收听
MainProvider.instance() {
this.readChats();
}
readChats() {
var query = APIs()
.chats
.collection
.where('users', arrayContainsAny: [Services().auth.currentUser().uid])
.orderBy('updatedAt', descending: true)
.limit(10);
if (this.lastChat != null) query = query.startAfterDocument(this.lastChat);
this._chatsStream = Services().crud.readLive(
stream: query.snapshots(),
onEmpty: () {
Funcs.log('EMP');
// chats.clear();
},
onAdded: (c) {
Funcs.log('ADD');
Chat chat = Chat.model(id: c.id, map: c.data());
this.chats.add(chat);
this.lastChat = c;
notifyListeners();
},
onModified: (c) {
Funcs.log('MOD');
Chat chat = Chat.model(id: c.id, map: c.data());
int index = this.chats.indexWhere((element) => element.chatID == chat.chatID);
chat.messages = this.chats[index].messages;
this.chats[index] = chat;
this.chats.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
notifyListeners();
},
onRemoved: (c) {
Funcs.log('REM');
Chat chat = Chat.model(id: c.id, map: c.data());
int index = this.chats.indexWhere((element) => element.chatID == chat.chatID);
this.chats.removeAt(index);
notifyListeners();
},
onFailure: (e) => print(e),
);
}