如何在 Flutter 中嵌套 StreamBuilder?
Posted
技术标签:
【中文标题】如何在 Flutter 中嵌套 StreamBuilder?【英文标题】:How can you nest StreamBuilders in Flutter? 【发布时间】:2019-12-10 04:42:31 【问题描述】:我需要将 2 个 Streams 组合起来以构建一个小部件,但与我见过的其他问题不同,我需要嵌套我的流。
我有一个从 Firestore 获取文档集合的流,还有一个依赖于第一个数据的流来获取文档的子集合。我想将它们组合成一个流,但它们需要嵌套,因为每个文档都有自己的文档子集。
Stream 1(从 FireStore 获取习惯集合):
Stream<List> getHabits()
final Stream<QuerySnapshot> documents = Firestore.instance
.collection("users")
.document('VtL1sxOoCOdJaOTT87IbMRwBe282')
.collection("habits")
.snapshots();
Stream<List> data = documents.map((doc)
List data;
final documents = doc.documents;
///Maybe this would work to get history of each doc?
for(int i = 0; i < documents.length; i++)
///not sure what to do
getHistory(documents[i].documentID, DateTime.utc(2019,7,7), DateTime.now());
data = documents.map((documentSnapshot) => documentSnapshot).toList();
return data;
);
return data;
Stream 2(在Stream 1中调用,以DocumentID
为参数,获取文档的子集合):
Stream<List> getHistory(String id, DateTime start, DateTime end) async*
await for (QuerySnapshot querySnapshot in Firestore.instance
.collection("users")
.document('VtL1sxOoCOdJaOTT87IbMRwBe282')
.collection("habits")
.document(id)
.collection("history")
.where('day', isGreaterThanOrEqualTo: start)
.where('day', isLessThanOrEqualTo: end)
.snapshots())
List history;
final documents = querySnapshot.documents;
history = documents.map((documentSnapshot) => documentSnapshot).toList();
yield history;
任何关于如何将这些流以嵌套格式组合成一个流以在颤振中与StreamBuilder
一起使用的任何帮助将不胜感激!'
编辑 我不确定我的工作方向是否正确,但我已尝试从 spenster 实施解决方案,这是我目前除了上述功能之外的功能。
StreamBuilder<List>(
stream: getHabits(),
initialData: [],
builder: (context, snapshot)
List<UserHabit> habits = [];
List<Widget> test = List.generate(snapshot.data.length, (index)
List<History> history = [];
DocumentSnapshot doc = snapshot.data[index];
return StreamBuilder(
stream: getHistory(doc.documentID, DateTime.utc(2019,7,7), DateTime.now()),
builder: (context, snapshot)
if (snapshot.hasError)
return new Text('Error: $snapshot.error');
switch (snapshot.connectionState)
case ConnectionState.waiting: return new Text('Loading...');
default:
if(!snapshot.data.isEmpty) //history collection exists
for(int i = 0; i < snapshot.data.length; i++)
//add to history
history.add(History(
day: snapshot.data[i]['day'].toDate(),
dateCompleted: snapshot.data[i]['dateCompleted'].toDate(),
morning: snapshot.data[i]['morning'],
afternoon: snapshot.data[i]['afternoon'],
evening: snapshot.data[i]['evening'],
anytime: snapshot.data[i]['anytime'],
));
habits.add(UserHabit(
name: doc['habit'],
color: doc['color'],
icon: doc['icon'],
repeat: doc['repeat'],
daily: doc['daily'],
weekly: doc['weekly'],
monthly: doc['monthly'],
time: doc['time'],
history: history,
));
print(habits); //returns each iteration of assembling the list
return Text("i dont want to return anything");
,
);
);
print(habits); //returns empty list before anything is added
return Column(
children: test,
);
,
),
UserHabits 和 History 的类可以共享,但它们只是分配类型并允许轻松访问的基本类。
【问题讨论】:
【参考方案1】:我使用嵌套的StreamBuilders
做了类似的事情。根据您希望Widget
s 的组织方式,您可以在外部StreamBuilder
内创建流。根据您澄清的 cmets,这是一种可能性:
@override
Widget build(BuildContext context)
var habits = Firestore.instance
.collection("users")
.document('VtL1sxOoCOdJaOTT87IbMRwBe282')
.collection("habits")
.snapshots();
return StreamBuilder<QuerySnapshot>(
stream: habits,
builder: (context, snapshot)
if (!snapshot.hasData)
return Text("Loading habits...");
return ListView(children: snapshot.data.documents.map((document)
var query = Firestore.instance
.collection("users")
.document('VtL1sxOoCOdJaOTT87IbMRwBe282')
.collection("habits")
.document(document.documentID)
.collection("history")
.where('day', isGreaterThanOrEqualTo: start)
.where('day', isLessThanOrEqualTo: end)
.snapshots();
return StreamBuilder<QuerySnapshot>(
stream: query,
builder: (context, snapshot)
if (!snapshot.hasData) return Text("Loading...");
// right here is where you need to put the widget that you
// want to create for the history entries in snapshot.data...
return Container();
,
);
).toList());
,
);
【讨论】:
谢谢!我会试一试,如果可行,我会将您的答案标记为正确!感谢您花时间回答问题! 只是出于好奇,有什么办法我不能在getHistory
StreamBuilder
中不返回任何内容吗?我需要使用history
数据列表来查看事情是否已完成,但我只在getHabits()
中为每个项目构建一个小部件
我也收到以下错误The element type 'Set<StreamBuilder<List>>' can't be assigned to the list type 'Widget'.
如果您只想要历史收藏中的一个文档,那么您可以使用 Firestore 来选择它(比如在查询中使用 .limit(1)),然后只构建一个小部件。这也应该顺便消除您也看到的其他错误。我会看看我是否可以更新答案...
我想我设法让这种方法起作用,但我觉得应该有一种方法可以嵌套流而不需要嵌套流构建器。或者firebase应该更容易访问子文档哈哈。非常感谢您抽出宝贵的时间,我会将其标记为正确的!大约一周以来一直在解决这个难题。【参考方案2】:
尝试将您的流与Observable.zip2(stream1,stream2,zipper)
或Observable.combineLatest2(streamA, streamB, combiner)
之类的内容合并。
欲了解更多信息,请查看post
【讨论】:
我喜欢这个方向,但第二个流取决于第一个流中项目的documentID
。第二个流对于每个项目都与第一个不同。我需要它们以某种方式嵌套而不是压缩以上是关于如何在 Flutter 中嵌套 StreamBuilder?的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 的嵌套 Navigator 结构中,如何获取特定的 Navigator?
如何在flutter中使用API调用嵌套的json数据?
如何在 Flutter 中使用 Firestone 的 streambuilder 获取嵌套文档?
如何在 Flutter 中获取嵌套 firebase 数据的所有子数据?