Firestore 分页文档列表在 Flutter 中的奇怪行为

Firestore paginated document list weird behaviour in Flutter

提问人:felon 提问时间:10/29/2023 更新时间:10/29/2023 访问量:36

问:

我是 Flutter 的新手,正在构建一个聊天应用程序来练习 firestore。我已经为数据实现了分页,但我看到了奇怪的行为,目前没有解决方案。当我同步文档列表时,它们以完美的顺序列出。但是当我将应用程序长时间置于后台,然后将其拉到前台时,某些项目的顺序不正确。我已经多次看到这种情况发生,如果应用程序在后台并且列表在 firestore 上更新并且我将应用程序放在前台,则一些以前同步的消息会出现在列表的末尾,例如,如果我同步 1,2,3,4,5,6,7 的列表并将应用程序置于后台并重新打开它,那么有时数据看起来像 1,2,4,5,6,7,3。我正在附上用于它的代码。

聊天小部件:

@override
initState() {
  super.initState();
  .....
  _chatViewModel.getMessages();
  _scrollController.addListener(_scrollListener);
} 

.............

void _scrollListener() async {
  _chatViewModel.getOldMessages(_scrollController.position.pixels,
        _scrollController.position.maxScrollExtent);
}

.............

child: StreamBuilder(
     stream: _chatViewModel.messageStream,
     builder: (context, snapshot) =>_setListWidget(snapshot))

.............

Widget _setListWidget(AsyncSnapshot<List<MessageV2>> snapshot) {
    if (snapshot.hasData && snapshot.data != null) {
      return ListView.builder(
          itemCount: snapshot.data!.length,
          controller: _scrollController,
          reverse: true,
          itemBuilder: (context, index) {
            return MessageWidget(msg: snapshot.data![index]);
          });
    } else {
      return Center(child: Text('No data...'));
    }
  }

ChatView模型:

我最近添加了一个 HashSet 作为故障安全措施来防止这种行为,但仍然会发生。

late Stream<List<MessageV2>> messageStream;
final StreamController<List<MessageV2>> _messageStreamProvidor = StreamController();
final _messageList = <MessageV2>[];

ChatViewModel(){
......
messageStream = _messageStreamProvidor.stream;
_messageStreamProvidor.add(_messageList);
}

getMessages() {
    _dbService.messages.listen((list) {
      try {
        var list1 = <MessageV2>[];
        for (var element in list) {
          if (!_messageSet.contains(element.id)) {
            list1.add(element);
            _messageSet.add(element.id);
          }
        }
        _messageList.insertAll(0, list1);
        _messageStreamProvidor.add(_messageList);
        _viewStateStreamProvidor.add(ViewState.viewVisible);
        if (list.isNotEmpty && (list.first.isMe || _count == 0)) {
          if (_count == 0) _count++;
          _scrollStreamProvidor.add(true);
        }
      } catch (e) {
        print(e);
      }
    });
  }

//Method to fetch the old messages.
getOldMessages(double pixels, double maxScrollExtent) async {
    if (pixels == maxScrollExtent && !_dbService.loading) {
      _messageLoaderProvidor.add(_dbService.loading);
      final list = await _dbService.getOldMessageListSnapshot();
      if (list != null && list.isNotEmpty) {
        for (var e in list) {
          if (!_messageSet.contains(e.id)) {
            _messageList.add(e);
            _messageSet.add(e.id);
          }
        }
        _messageStreamProvidor.add(_messageList);
        _messageLoaderProvidor.add(_dbService.loading);
      }
    }
  }

数据库服务:

Stream<List<MessageV2>> get messages {
    return _messageCollection
        .orderBy('timestamp', descending: true)
        .limit(_messageLimit)
        .snapshots()
        .map(_messageListFromSnapshot);
}

List<MessageV2> _messageListFromSnapshot(QuerySnapshot snapshot) {
    final list = <MessageV2>[];
    _lastDoc ??= snapshot.docs.last;
    for (var e in snapshot.docChanges) {
      switch (e.type) {
        case DocumentChangeType.added:
          list.add(MessageV2.fromMap(e.doc, uid, true));
          print('added');
          break;
        case DocumentChangeType.modified:
          print('modified');
          break;
        case DocumentChangeType.removed:
          print('removed');
          break;
      }
    }
    return list;
 }

Future<List<MessageV2>?> getOldMessageListSnapshot() async {
    if (!loading && _lastDoc != null) {
      loading = true;
      var data = await _messageCollection
          .orderBy('timestamp', descending: true)
          .startAfterDocument(_lastDoc!)
          .limit(_messageLimit)
          .get();
      loading = false;
      if (data.docs.isNotEmpty) {
        _lastDoc = data.docs.last;
        return _setChatListFromQuerySnapshot(data);
      }
    }
    loading = false;
    return null;
  }

当代码停留在前台时,它绝对可以正常工作。我可以完美地发送和接收消息,分页也是正确的。只有当它长时间保持在后台时,它才会开始显示此行为。我已经尝试了多种方法来解决这个问题,但它一直在蔓延。当应用程序在后台设置地理位置时,我是否应该清除流,并在前台重新注册它?我在这里有点无知。

Flutter google-cloud-firestore 分页 聊天

评论


答: 暂无答案