多个流到 Firebase 文档而不进行处理

Posted

技术标签:

【中文标题】多个流到 Firebase 文档而不进行处理【英文标题】:Multiple streams to firebase documents without disposing 【发布时间】:2020-06-03 01:19:42 【问题描述】:

我正在尝试将聊天功能添加到我的应用程序中。 当我的用户开始与新用户聊天时,我会在我的 Firebase 数据库中创建一个具有唯一 ID 的聊天室。我希望我的用户收到有关聊天室文档的任何更新(例如:新消息)的通知,因此当我创建聊天室时,我还会为该聊天室文档创建一个新流。在不处理流的情况下不断收听具有不同流的许多文档是否存在问题(因为我想获得用户所属的任何聊天室的最新结果。)

这是我的聊天室屏幕代码:

import 'package:flutter/material.dart';
import '../models/databse_management.dart';


class ChatroomScreen extends StatefulWidget 
  static const String routeName = "/chatroom_screen";
  @override
  _ChatroomScreenState createState() => _ChatroomScreenState();


class _ChatroomScreenState extends State<ChatroomScreen> 
  TextEditingController _messageTextEditingController = TextEditingController();
  bool isChatroomExists;
  Stream chatroomDocStream; //my initial stream variable which is null
  @override
  Widget build(BuildContext context) 
    final Map<String, dynamic> passedArguments =
        ModalRoute.of(context).settings.arguments;
    //sedner details can be retrieved from currentUserDetails
    final String senderId = passedArguments["senderId"];
    final List<String> receiversIds = passedArguments["receiverIds"];
    final String senderUsername = passedArguments["senderUsername"];
    final List<String> receiverUsernames = passedArguments["receiverUsernames"];
    final String chatroomId = passedArguments["chatroomId"];
    if(chatroomDocStream == null)
      chatroomDocStream = Firestore.instance.collection("chatrooms").document(chatroomId).snapshots(); //if no stream was created before (first time we build the widget), we connect a stream to this chatroom documentspecified with chatroomId
    
    isChatroomExists = isChatroomExists == null

        ? passedArguments["isChatroomExists"]
        : isChatroomExists;

    final Image senderProfilePictureUrl =
        passedArguments["senderProfilePicture"];
    final List<Image> receiverProfilePictures =
        passedArguments["receiverProfilePictures"];
    final mediaQuery = MediaQuery.of(context).size;
    final ThemeData theme = Theme.of(context);

    //we get the values from the passed argument map
    if (isChatroomExists) 
      //load the previous chats
    
    return Scaffold(
      appBar: AppBar(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            CircleAvatar(
              backgroundImage: receiverProfilePictures[0]
                  .image, //right now only for 1 receiver but change it for multi members later
            ),
            Container(
              child: Text(receiverUsernames[0]),
              margin: const EdgeInsets.only(left: 10),
            ),
          ],
        ),
      ),
      body: //to do=> create a stream that is listening to the chatroom document for any changes
          Stack(
        children: <Widget>[
         StreamBuilder(
            //updates the chats whenever data of the chatroom document changes
            stream: chatroomDocStream,
            builder: (context, snapShot) 
              return Column(
                children: <Widget>[
                  Center(child: const Text("My chats"))
                  //message widgets go here
                ],
              );
            ,
          ),
          Positioned(
            //positioned is used for positioning the widgets inside a stack. bottom: 10 means 10 pixel from bottom
            bottom: 0,
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
              width: mediaQuery.width, //takes the total width of the screen
              decoration: BoxDecoration(
                color: theme.primaryColor.withOpacity(0.3),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Expanded(
                    //always takes the remaining space (textField widget use this as its size https://***.com/questions/45986093/textfield-inside-of-row-causes-layout-exception-unable-to-calculate-size)
                    child: Container(
                      padding: const EdgeInsets.symmetric(
                          horizontal:
                              10), //horizontal padding for the textfield widget
                      decoration: BoxDecoration(
                        color: theme.accentColor,
                        borderRadius: BorderRadius.circular(25),
                        border: Border.all(width: 2, color: theme.primaryColor),
                      ),
                      child: TextField(
                        minLines: 1,
                        maxLines: 5,
                        controller: _messageTextEditingController,
                        decoration: const InputDecoration(
                            hintText: "Type something here...",
                            border: InputBorder
                                .none //removes all the border for textfield widget
                            ),
                      ),
                    ),
                  ),
                  Container(
                    child: Row(
                      //another row for buttons to be treated all toghether as a container in the parent row
                      children: <Widget>[
                        IconButton(
                          icon: const Icon(Icons.add),
                          onPressed: () 
                            //add media like image or pictures
                          ,
                        ),
                        IconButton(
                          icon: const Icon(Icons.camera_alt),
                          onPressed: () 
                            //take picture or video
                          ,
                        ),
                        IconButton(
                          icon: const Icon(Icons.send),
                          onPressed: () async 
                            if (_messageTextEditingController.text
                                .trim()
                                .isEmpty) 
                              return;
                            
                            try 
                              await DatabaseManagement().sendMessage(
                                membersIds: [
                                  senderId,
                                  ...receiversIds
                                ], //extracts all the members of the list as seperate String items
                                //to do=>later on we have to get a list of the members as well
                                isChatroomExists: isChatroomExists,
                                chatroomId: chatroomId,
                                messageContent:
                                    _messageTextEditingController.text,
                                senderId: senderId,
                                timestamp: Timestamp
                                    .now(), //it's from firebase and records the time stamp of the sending message
                              );
                              if (isChatroomExists != true) 
                                isChatroomExists =
                                    true; //after we sent a messsage, we 100% created the chatroom so it becomes true
                              
                             catch (e) 
                              print(
                                e.toString(),
                              );
                              return;
                            
                          ,
                        )
                      ],
                    ),
                  )
                ],
              ),
            ),
          ),
        ],
      ),
    );
  

我们的想法是拥有类似 WhatsApp 的东西,您可以在您所属的任何聊天室中收到任何更新的通知。

【问题讨论】:

【参考方案1】:

您可以创建大量快照侦听器,但 Google 建议每个客户端限制为 100 个快照侦听器:

来源:https://cloud.google.com/firestore/docs/best-practices?hl=en#realtime_updates

【讨论】:

从不处理这些流有问题吗?我可以让它们一直打开吗? StreamBuilder 小部件在绘制时侦听 Stream,并在处理后自动关闭 Stream。如果不是同时绘制很多StreamBuilders是没有问题的

以上是关于多个流到 Firebase 文档而不进行处理的主要内容,如果未能解决你的问题,请参考以下文章

为动态链接设置自定义路由,而不使用 Firebase 托管

Swift 2.3 pod 更新后使用未解析的标识符 Firebase 'FIR'

将多个图像存储到 Firebase 并获取 url

未处理的异常:NoSuchMethodError:在 null 上调用了方法“toRawHandle”

iOS - 处理 Internet 断开连接,Firebase

如何在 Swift 上将具有自定义 ID 的文档添加到 Firebase (Firestore)