我不弄清楚如何在不破坏实时侦听器的情况下对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);
}
}
似乎需要以某种方式将这两种方法结合起来才能达到预期的效果,但是经过两天的尝试,我无法确定如何做到这一点。