将流合并在一起以创建分页ListView



我正在构建一个ListView,其中包含存储在Firestore中的Hour项目列表。我可以用StreamBuilder创建它,但考虑到Hours集合包含数千个文档,有必要引入分页以减少不必要的读取。

我的想法是创建一个流(mainStream(,其中包含过去24小时的查询项。如果用户向下滚动20个项目,我将通过将mainStream与一个新流合并来扩展它,并添加20个额外的元素。然而,它似乎不起作用——流中只有前24个项目,合并似乎没有任何影响。

为什么我想要对流进行分页,而不是列表?小时项目可以在其他设备上更改,我需要流来注意更改。

我已经坚持了一天多了,其他问题也无济于事——我们非常感谢任何帮助。

class TodayPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Today'),
),
body: _buildContents(context),
);
}
Widget _buildContents(BuildContext context) {
final database = Provider.of<Database>(context, listen: true);
DateTime startingHour =
dateHourFromDate(DateTime.now()).subtract(Duration(hours: 24));
DateTime beforeHour;
// Stream with items for last 24 hours
// hoursStream returns Stream<List<Hour>> from startingHour till beforeHour
Stream mainStream = database.hoursStream(startingHour: startingHour.toString());
return StreamBuilder<List<Hour>>(
stream: mainStream,
builder: (context, snapshot) {
if (snapshot.data != null) {
final List<Hour> hours = snapshot.data;
final allHours = hours.map((hour) => hour.id).toList();
return ListView.builder(
// chacheExtent to make sure that itemBuilder will not build items for which we have not yet fetched data in the new stream
cacheExtent: 5,
itemBuilder: (context, index) {
// if itemBuilder is reaching till the end of items in mainStream, extend mainStream by items for the following 24 hours
if (index % 20 == 0) {
beforeHour = startingHour;
startingHour = startingHour.subtract(Duration(hours: 20));
// doesn't seem to work - snapshot contains elements only from the original mainStream
mainStream.mergeWith([
database.hoursStream(
beforeHour: beforeHour.toString(),
startingHour: startingHour.toString())
]);
}
return Container(); // placeholder for a widget with content based on allHours
});
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}
}

小时流的实施:

Stream<List<Hour>> hoursStream({
String startingHour,
String beforeHour,
}) =>
_service.collectionStream(
path: APIPath.hours(uid),
builder: (data, documentId) => Hour.fromMap(data, documentId),
queryBuilder: (query) => query
.where('id', isGreaterThanOrEqualTo: startingHour)
.where('id', isLessThan: beforeHour));

最后收集流

Stream<List<T>> collectionStream<T>({
@required String path,
@required T Function(Map<String, dynamic> data, String documentId) builder,
Query Function(Query query) queryBuilder,
int Function(T lhs, T rhs) sort,
}) {
Query query = FirebaseFirestore.instance.collection(path);
if (queryBuilder != null) {
query = queryBuilder(query);
}
final snapshots = query.snapshots();
return snapshots.map((snapshot) {
final result = snapshot.docs
.map((snapshot) => builder(snapshot.data(), snapshot.id))
.where((value) => value != null)
.toList();
if (sort != null) {
result.sort(sort);
}
return result;
});
}

如果你想组合流,你需要使用rxdart包

导入包:

import 'package:rxdart/rxdart.dart';

然后使用以下代码组合流

CombineLatestStream.list([stream1, stream2,.....]);

想要监听更改,请使用以下代码

CombineLatestStream.list([stream1, stream2,.....]).listen((data) {
data.elementAt(0); // stream1
data.elementAt(1); // stream2
});

如果侦听方法不能按您的预期工作,则有其他方法可用

有关更多信息,请查看此链接:https://pub.dev/packages/rxdart

据我所知,Stream没有mergeWith方法,所以我不知道它是您创建的扩展还是来自库的扩展,但有一件事您忘记了setState

if (index % 20 == 0) {
beforeHour = startingHour;
startingHour = startingHour.subtract(Duration(hours: 20));
setState(() {
mainStream.mergeWith([
database.hoursStream(
beforeHour: beforeHour.toString(),
startingHour: startingHour.toString())
]);
});
}

顺便说一句,我喜欢你用collectionStream方法做的事情。非常漂亮的编码。

最新更新