繁体   English   中英

StreamBuilder 在不应该有数据的时候有数据

[英]StreamBuilder has data when it shouldn't

我正在使用 Firebase 实时数据库向我的应用程序添加聊天功能。 在数据库中,我有以下数据:

{
    events: {
        "event-uuid1": {
            "chat-uuid1": {
                "message": "hey"
            },
            "chat-uuid2": {
                "message": "hey again"
            }
        }
    }
}

在我的 Flutter 应用程序中,我有这个 StreamBuilder(我知道这很长,我不确定问题出在哪里,所以提供更多而不是更少):

class _EventChatScreenState extends ConsumerState<EventChatScreen> {
    FirebaseDatabase dbInstance = FirebaseDatabase.instance;
    late TextEditingController _messageFieldController;
    late DatabaseReference eventDbRef;

    @override
    void initState() {
        super.initState();
        _messageFieldController = TextEditingController();
        eventDbRef = dbInstance.ref("none");
    }

    @override
    void dispose() {
        _messageFieldController.dispose();
        super.dispose();
    }

    Map<String, ChatMessage> chatMessages = {};

    @override
    Widget build(BuildContext context) {
        final user = ref.watch(userProvider);
        final event = ModalRoute.of(context)!.settings.arguments as EventRepository;
        if (eventDbRef.path == "none") {
            print("IT IS NONE");
            eventDbRef = dbInstance.ref("/events/${event.event.eventId}/");
            print(eventDbRef.path); // Print's correct value
        }
        
        return StreamBuilder(
            stream: eventDbRef.onChildAdded,
            builder: (context, snapshot) {
                if (chatMessages == {}) {
                    return const Text("Loading...");
                }

                DatabaseEvent data;

                if (snapshot.hasData) {
                    data = snapshot.data as DatabaseEvent;
                    ChatMessage newChatMessage = ChatMessage(
                        chatMessageId: "",
                        userId: "",
                        displayname: "",
                        message: "",
                        datetime: "",
                    );

                    for (var child in data.snapshot.children) {
                        switch (child.key) {
                            case "chatMessageId":
                                newChatMessage.chatMessageId = child.value.toString();
                            break;
                        case "userId":
                            newChatMessage.userId = child.value.toString();
                            break;
                        case "displayName":
                            newChatMessage.displayname = child.value.toString();
                            break;
                        case "message":
                            newChatMessage.message = child.value.toString();
                            break;
                        case "datetime":
                            final datetime = DateTime.parse(child.value.toString());
                            final DateFormat formatter = DateFormat('h:mm aa');
                            final String formatted = formatter.format(datetime);
                            newChatMessage.datetime = formatted;
                            break;
                        default:
                    }
                }
   
                if (chatMessages[data.snapshot.key] == null) {
                    chatMessages[data.snapshot.key!] = newChatMessage;
                }
            }

            return ListView.builder(
                itemCount: chatMessages.length,
            itemBuilder: (context, index) {
                String key = chatMessages.keys.elementAt(index);
                if (chatMessages[key]!.userId == user.user.userId) {
                    return UnconstrainedBox(
                        alignment: Alignment.centerRight,
                        child: Container(
                            margin: const EdgeInsets.symmetric(vertical: 5),
                            child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                    Container(
                                        padding: const EdgeInsets.only(left: 10),
                                        child: Text(chatMessages[key]!.displayname),
                                    ),
                                    Container(
                                        padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 15),
                                        decoration: BoxDecoration(
                                            borderRadius: const BorderRadius.all(
                                                Radius.circular(20),
                                            ),
                                            color: Theme.of(context).colorScheme.primary,
                                        ),
                                        child: Text(chatMessages[key]!.message,
                                        style: TextStyle(
                                        color: Theme.of(context).colorScheme.onPrimary,
                                    ),
                                ),
                            ),
                            Container(
                                padding: const EdgeInsets.only(left: 10),
                                child: Text(chatMessages[key]!.datetime),
                            ),
                        ],
                    ),
                ),
            );
        }
    },
);
},
),

问题是,当用户进入聊天屏幕时,其中一条消息已经出现在聊天中。 我希望什么都没有,因为我没有在任何地方设置任何初始数据,没有使用实时数据库的持久性,也没有使用我自己的本地数据库。

我对 StreamBuilders 的理解是,他们只会在新数据进来时获取新数据,而不是可能已经存在并因此不会通过它发送的数据(即,当发送新的聊天消息时,stream 应该会收到它,这是有效的,但它不应接收数据库中已有的聊天消息消息)。 如果这种理解是错误的,那么尽管数据库中有 2、3、4 等,为什么我只收到一条消息?

也许我理解/使用 StreamBuilders、Firebase 实时数据库,或两者都不正确?

也许您对 streambuilder 的理解是错误的。

假设您使用FutureBuilder ,它会等到未来结束,然后相应地构建小部件,但如果数据库中发生某些变化,它不会再次构建,但对于StreamBuilder ,它基本上会监听(并从中获取初始数据stream,这里是你的db )到 stream 并在它发生变化或新数据添加到 stream(这里是database )时构建,它将获取更新的数据并再次构建小部件。

在这里阅读:
https://firebase.flutter.dev/docs/firestore/usage/#realtime-changes

将此eventDbRef.onChildAdded分配给 initState 中的变量,然后将该变量用作 streambuilder 中的 stream 参数。 在 Streambuilder 中调用 db 会导致它在每次构建小部件树时重新运行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM