项目的实现效果
项目的实现效果如上图所示。简单介绍一下项目:假设用户A和用户B是朋友关系,用户A登陆之后朋友列表中有用户B,用户B登陆之后朋友列表中有用户A。点击朋友列表中的一个朋友,可以打开和朋友之间的聊天界面。用户A向用户B发送消息之后,用户B查看消息之后,用户A的聊天界面会显示为已读。
用户之间的聊天记录
上图是用户之间的聊天数据示例。Realtime Database内部是json数据结构,json数据结构是分层的。chats代表所有单人之间的聊天结合。图中的1代表id,两个用户之间的聊天的索引或者key,我们把用户的id和"_"连接形成聊天记录的id。示例代码,如下:
dart
String generateChatId(String uid1, String uid2) {
final uids = [uid1, uid2]..sort();
return '${uids[0]}_${uids[1]}';
}
注意两个用户的uid需要排序,因为两个用户uid通过"_"连接组合可能有两种可能,如果用sort排序就能保证唯一性。 图中的2代表一条聊天信息的id。图中的3代表消息接受方的id,也就是朋友的id,属性值true代表朋友已经读过这条消息。其中还包括发送方用户的id:senderId,聊天的内容:text,发送消息的时间戳timestamp。
用户之间发送消息
dart
Future<void> sendMessage(String myUid, String otherUid, String text) async {
final chatId = generateChatId(myUid, otherUid);
final ref = FirebaseDatabase.instance.ref('chats/$chatId/messages').push();
await ref.set({
'senderId': myUid,
'text': text,
'timestamp': ServerValue.timestamp,
'readBy': {otherUid: false},
});
}
示例代码如上所示,也就是向聊天集合中的messages添加一条聊天记录,key是自动生成的唯一的字符串。Realtime Database是低延迟,自动同步的数据库,只要本地数据库数据变动就会收到变化通知,如果网络连接正常,数据会同步到Realtime Database server,同时通知监听数据变化的client端,这在软件设计领域有点像订阅者通知模式,只不过是数据库的订阅通知。用户A向用户B发送消息,用户B收到消息的延迟大概是秒级单位。
标记消息已读
dart
String chatId = generateChatId(
context.read<UserUid>().friend!.uid,
_auth.currentUser!.uid,
);
DatabaseReference ref = FirebaseDatabase.instance.ref('chats/$chatId/messages/${message.key}/readBy');
final readBy = message.value['readBy'] as Map<dynamic, dynamic>?;
if (readBy != null && readBy[_auth.currentUser!.uid] == false) {
await ref.update({
_auth.currentUser!.uid: true,
});
}
只有readBy中属性名称和当前用户的id一样,并且它的值为false,才会在这条消息显示在屏幕的时候(用户查看)标记为已读。
消息的排序
ini
final messages = data.entries.toList()
..sort((a, b) {
final tsA = a.value['timestamp'] ?? 0;
final tsB = b.value['timestamp'] ?? 0;
return tsA.compareTo(tsB);
});
消息按照时间先后顺序排序,代码逻辑如上所示。
参考资料
项目已经上传到github上,地址是github.com/caiweihao/f... firebase.google.com/docs/databa...