繁体   English   中英

如何刷新 firebase streambuilder 并减少文档读取次数

[英]How to refresh a firebase streambuilder and reduce the number of document reads

我正在努力与 Flutter 建立聊天,我打算使用 firestore。 我有一个 streambuilder,我将读取的文档数量限制为 20 个。聊天工作正常,并向我显示了最后 20 条消息。 现在我想在滚动到顶部后立即添加接下来的 20 条旧消息。

我有一个有效的解决方案,但我不确定它是否是最好的。 我最担心的是每次更改限制值时我进行了多少次读取。 我是在阅读 20 篇新文章还是在阅读 40 篇新文档? 如果我滚动更多,我是否使用了 60 次读取?

看下面我的代码

void initState() {
    maxMessageToDisplay = 20;
    _scrollController = ScrollController();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
        setState(() {
          maxMessageToDisplay += 20;
        });
      }
    });
    super.initState();
}

Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _firestore.collection('chat').limit(maxMessageToDisplay).orderBy('timestamp', descending: true).snapshots(),
      builder: (context, snapshot) {
     
        final messages = snapshot.data.documents;

        messages.sort((a, b) => b.data['timestamp'].compareTo(a.data['timestamp']));
        var format = new DateFormat("Hm");

        List<MessageBubble> messageBubbles = [];
        for (var message in messages) {
          final messageText = message.data['text'];
          final messageSender = message.data['sender'];
          final messagePhoto = message.data['photo'];
          final messageUserId = message.data['uid'];

          final messageTime = format.format(DateTime.fromMillisecondsSinceEpoch(message.data['timestamp'], isUtc: false));    

          final messageBubble = MessageBubble(
            sender: messageSender,
            text: messageText,
            photo: messagePhoto,
            time: messageTime,
            userId: messageUserId,
          );
          messageBubbles.add(messageBubble);
        }
        return Expanded(
          child: ListView(
            controller: _scrollController,
            reverse: true,
            padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
            children: messageBubbles,
          ),
        );
      },
    );
  }
}

如果侦听器超过 30 分钟没有断开连接,您不必担心,因为 Firebase 仅在文档更改时才计算新读取。 所以在你的情况下,如果你已经阅读了 20 个文档,然后用户滚动并获得 20 个以上,你将只有 40 个而不是 60 个阅读。 您可以在此处阅读有关 firebase 计费的更多信息

您应该能够通过修改您在 stream 构建器中使用的 stream 来执行此操作。

您应该在两个源之间创建一个组合 stream 并在每次源带来新数据时推送新值。 为此,您可以使用rxDart插件中的BehaviorSubjects (这很简单,并且比标准流好一点,尽管您可以使用标准 dart 流做任何事情)。

这是一个示例代码:

List<FireStoreItem> fireStoreItems = [];

BehaviorSubject<List<FireStoreItem>> OlderItemsStream = new BehaviorSubject<List<FireStoreItem>>():

BehaviorSubject<List<FireStoreItem>> finalItemsStream = Rx.combileLatest2(
_firestore.collection('chat').limit(maxMessageToDisplay).orderBy('timestamp', descending: true).snapshots(),
OlderItemsStream, (a,b)=>a.addAll(b))

最终的 stream 是原始消息 stream 和旧消息 stream 的组合。每当其中一个流获得新值时,都会生成一个新快照。

Rx.combineLatest2中的最后一个参数是流的映射,在这里我们基本上将旧消息快照数据添加到第一个流的快照数据中,从而创建一个包含最新消息和旧消息的列表,并将其作为一个新值组合在一起并相应地更新 stream 构建器。

您的 stream 构建器应该只将finalItemsStream作为源 stream。

至于滚动触发器,你需要滚动到最后才能触发从 FireStore 中提取旧消息,你可以在滚动 controller 上设置一个监听器并检查atEdge bool,它会告诉你是否到达滚动边缘或不。

这是一个示例代码:

scrollController.addListener(() {
      if(scrollController.position.atEdge){
        //create a fireStore call and add the resulting data to the olderItems stream
        FireStoreCall().then((data){
          OlderItemsStream.add(oldMessages);
        });
      }
    });

注意: scrollController应该与listView中使用的相同

暂无
暂无

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

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