如何刷新Firebase StreamBuilder并减少文档读取次数

时间:2020-08-20 16:04:12

标签: firebase flutter google-cloud-firestore

我正在与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,
          ),
        );
      },
    );
  }
}

2 个答案:

答案 0 :(得分:2)

如果侦听器在30分钟内没有断开连接,则不必担心,因为Firebase仅在文档更改时才计入新的读取次数。 因此,在您的情况下,如果您阅读了20个文档,则用户滚动并获得了20个文档,则您只能阅读40次,而不阅读60次。 您可以阅读有关Firebase计费here

的更多信息

答案 1 :(得分:1)

通过修改流构建器中正在使用的流,您应该能够做到这一点。

您应该在两个来源之间创建一个合并的流,并在每次来源带来新数据时推送新值。为此,您可以使用BehaviorSubjects插件中的rxDart(这很容易,并且比标准流还好,尽管您可以使用标准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))

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

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

您的流生成器​​应仅将finalItemsStream作为源流。

对于滚动触发器,您需要滚动到最后以触发从FireStore提取旧消息,您可以在滚动控制器上设置侦听器并检查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

中使用的相同