Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
多个流到firebase文档,无需处理_Firebase_Flutter_Google Cloud Firestore_Stream - Fatal编程技术网

多个流到firebase文档,无需处理

多个流到firebase文档,无需处理,firebase,flutter,google-cloud-firestore,stream,Firebase,Flutter,Google Cloud Firestore,Stream,我正在尝试将聊天添加到我的应用程序中。 当我的用户开始与新用户聊天时,我会在Firebase数据库中创建一个具有唯一id的聊天室。我希望聊天室文档的任何更新(例如:新消息)都会通知我的用户,因此当我创建聊天室时,我也会为该聊天室文档创建一个新流。在不处理流的情况下,不断地侦听具有不同流的多个文档是否有问题(因为我想获得用户所属聊天室的最新结果。) 这是我的聊天室屏幕代码: import 'package:flutter/material.dart'; import '../models/data

我正在尝试将聊天添加到我的应用程序中。 当我的用户开始与新用户聊天时,我会在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://stackoverflow.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;
                            }
                          },
                        )
                      ],
                    ),
                  )
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}
导入“包装:颤振/材料.省道”;
导入“../models/database_management.dart”;
类聊天室屏幕扩展StatefulWidget{
静态常量字符串routeName=“/chatroom\u screen”;
@凌驾
_聊天室屏幕状态createState()=>\u聊天室屏幕状态();
}
类\u聊天室屏幕状态扩展状态{
TextEditingController_messageTextEditingController=TextEditingController();
布尔是存在的;
Stream chatroomDocStream;//我的初始流变量为null
@凌驾
小部件构建(构建上下文){
最终地图通过了辩论=
ModalRoute.of(context.settings.arguments);
//可以从currentUserDetails检索sedner详细信息
最后一个字符串senderId=passedArguments[“senderId”];
最终名单接收方=通过的参数[“接收方”];
最后一个字符串senderUsername=passedArguments[“senderUsername”];
最终列表接收者用户名=传递的参数[“接收者用户名”];
最后一个字符串chatroomId=passedArguments[“chatroomId”];
if(chatroomDocStream==null){
chatroomDocStream=Firestore.instance.collection(“chatrooms”).document(chatroomId).snapshots();//如果之前没有创建流(第一次构建小部件),我们会将一个流连接到使用chatroomId指定的这个chatroomdocument
}
isChatroomExists=isChatroomExists==null
?通过的参数[“isChatroomExists”]
:IsChatRoom存在;
最终图像发送者ProfilePictureUrl=
已通过的辩论[“发件人档案图片”];
最终接收名单=
通过的辩论[“接收者档案图片”];
final mediaQuery=mediaQuery.of(context).size;
最终主题数据主题=theme.of(上下文);
//我们从传递的参数映射中获取值
如果(isChatroomExists){
//加载以前的聊天记录
}
返回脚手架(
appBar:appBar(
标题:世界其他地区(
mainAxisAlignment:mainAxisAlignment.start,
儿童:[
圆形(
背景图片:receiverProfilePictures[0]
.image,//目前仅针对1个接收器,但稍后针对多个成员更改它
),
容器(
子项:文本(接收方用户名[0]),
边距:仅限常量边集(左:10),
),
],
),
),
body://to do=>创建一个正在侦听聊天室文档的流,以获取任何更改
堆叠(
儿童:[
StreamBuilder(
//每当聊天室文档的数据发生更改时,更新聊天室
流:聊天室docstream,
生成器:(上下文,快照){
返回列(
儿童:[
中心(子:常量文本(“我的聊天”))
//消息小部件放在这里
],
);
},
),
定位(
//定位用于在堆栈中定位小部件。底部:10表示距离底部10像素
底部:0,
子:容器(
填充:常量边集。对称(水平:10,垂直:5),
宽度:mediaQuery.width,//获取屏幕的总宽度
装饰:盒子装饰(
颜色:主题。原色。不透明度(0.3),
),
孩子:排(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
儿童:[
扩大(
//始终将剩余空间(textField小部件)用作其大小https://stackoverflow.com/questions/45986093/textfield-inside-of-row-causes-layout-exception-unable-to-calculate-size)
子:容器(
填充:const EdgeInsets.symmetric(
水平:
10) ,//textfield小部件的水平填充
装饰:盒子装饰(
颜色:theme.accentColor,
边界半径:边界半径。圆形(25),
边框:边框.all(宽度:2,颜色:主题.primaryColor),
),
孩子:TextField(
小姑娘:1,
最大行数:5,
控制器:_messageTextEditingController,
装饰:常量输入装饰(
hintText:“在此处键入内容…”,
边框:输入边框
.none//删除textfield小部件的所有边框
),
),
),
),
容器(
孩子:排(
//另一行按钮将作为父行中的容器一起处理
儿童:[
图标按钮(
图标:常量图标(Icons.add),
已按下:(){
//添加图像或图片等媒体
},
),
图标按钮(
图标:常量图标(Icons.camera\u alt),
已按下:(){
//拍照或录像