如何在ListView.Builder中对Firestore数据进行分页并在Flutter中仍获取实时更新?

时间:2019-07-25 02:13:06

标签: firebase flutter google-cloud-firestore

我不弄清楚如何在不破坏实时侦听器的情况下对Firestore数据进行分页。数据将传递到StreamBuilder并显示在ListView.builder中。当用户达到maxScrollExtent时,我正在尝试获取下一组数据。

我了解如何使用startAfter和Firestore限制进行分页。如果我将获取的数据传递给StreamController并在StreamBuilder中使用它,则分页效果很好,但是Firestore不会将任何更新发送到设备。

如果我将Firestore.instance。(...)。snapshots()直接传递给StreamBuilder(不使用StreamController),那么我会从服务器获取更新,但是分页就搞砸了。 UI被重建,并且我被发送到列表的顶部。

使用StreamController

final int limit = 2;
final _list = List<DocumentSnapshot>();
final _listController = StreamController<List<DocumentSnapshot>>.broadcast();
DateTime startAt;
bool _isAllDataFetched = false;

Stream<List<DocumentSnapshot>> get listStream => _listController.stream;

void initState() {
    super.initState();
    _eventDao
        ?.getAllEventMedia(event?.id ?? "",
            startAfter: startAt?.millisecondsSinceEpoch, limit: limit)
        ?.then((QuerySnapshot querySnapshot) {
      _list.addAll(querySnapshot.documents);
      _listController.sink.add(_list);
    })?.catchError((error) {
      print(error);
    });
  }

Widget build(BuildContext context) {
    return StreamBuilder<List<DocumentSnapshot>>(
      stream: listStream,
      builder: (BuildContext context, AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
        if (snapshot.hasError) {
          return ErrorPage(imageAsset: AssetResources.failed);
        }

        if (snapshot.hasData &&
            snapshot.data.isNotEmpty &&
            snapshot.connectionState == ConnectionState.active) {
          startAt = DateTime.fromMillisecondsSinceEpoch(
            snapshot.data.last.data[EventMediaSchema.creationDate],
          );
          return MediaDisplayManagerAlt(
            documents: snapshot.data,
            atBottom: _fetchNextDocumentSet,
          );
        }

        if (snapshot.hasData && snapshot.connectionState == ConnectionState.active) {
          _isAllDataFetched = true;
        }

        return Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Center(
                child: Text("NO MEDIA YET"),
              ),
            ],
          ),
        );
      },
    );

void _fetchNextDocumentSet() async {
    if (!_isAllDataFetched) {
      QuerySnapshot querySnapshot = await _eventDao?.getAllEventMedia(event?.id ?? "",
          startAfter: startAt?.millisecondsSinceEpoch, limit: limit);
      _list.addAll(querySnapshot.documents);
      _listController.sink.add(_list);
    }
  }

将快照传递到StreamBuilder

final int limit = 2;
DateTime startAt;
bool _isAllDataFetched = false;

Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _eventDao?.(event?.id ?? "",
            startAfter: startAt?.millisecondsSinceEpoch, limit: limit),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (snapshot.hasError) {
          return ErrorPage(imageAsset: AssetResources.failed);
        }

        if (snapshot.hasData && snapshot.data.documents.isNotEmpty) {
          return MediaDisplayManagerAlt(
            documents: snapshot.data.documents,
            atBottom: _fetchNextDocumentSet,
          );
        }

        return Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Center(
                child: Text("NO MEDIA YET"),
              ),
            ],
          ),
        );
      },
    );
  }

void _fetchNextDocumentSet() async {
    if (!_isAllDataFetched) {
      QuerySnapshot querySnapshot = await _eventDao?.getAllEventMedia(event?.id ?? "",
          startAfter: startAt?.millisecondsSinceEpoch, limit: limit);
      _list.addAll(querySnapshot.documents);
      _listController.sink.add(_list);
    }
  }

似乎需要以某种方式将这两种方法结合起来才能达到预期的效果,但是经过两天的尝试,我无法确定如何做到这一点。

0 个答案:

没有答案