Flutter - 从 Stream 接收然后修改数据
Posted
技术标签:
【中文标题】Flutter - 从 Stream 接收然后修改数据【英文标题】:Flutter - Receive and then modify data from Stream 【发布时间】:2020-11-14 12:51:57 【问题描述】:我正在尝试执行以下操作:
-
监听 Firestore 流,以便在添加新文档时,StreamBuilder 将接收它、修改它,然后呈现它。
“修改”获取包含 Firestore UID 的 Stream 数据,使用该 UID 从 Firestore 获取数据,然后使用该数据填充 StreamBuilder。
所以流程是:添加新文档 -> 流获取文档 -> 函数从该文档获取 UID -> 函数使用该 UID 从 Firestore 获取更多数据 -> 函数返回以使用该新数据填充 StreamBuilder。
我当前的设置如下 - 可行,但 FutureBuilder 显然在每次重建小部件时都会调用 Firestore,而没有人想要这样。
Stream<QuerySnapshot> upperStream;
void initState()
super.initState();
upperStream = aStream();
Stream<QuerySnapshot> aStream()
return Firestore.instance
.collection('FirstLevel')
.document(ownUID (not related to stream))
.collection('SecondLevel')
.snapshots();
Future<List> processStream(List streamData) async
List futureData = List();
for (var doc in streamData)
Map<String, dynamic> dataToReturn = Map<String, dynamic>();
DocumentSnapshot userDoc = await Firestore.instance
.collection('FirstLevel')
.document(OTHER USER'S UID FROM STREAM)
.get();
dataToReturn['i'] = userDoc['i'];
futureData.add(dataToReturn);
return futureData;
...
...
//The actual widget
Expanded(
child: StreamBuilder(
stream: upperStream,
builder: (context, snapshot)
// Error/null handling
return FutureBuilder(
future: processStream(snapshot.data.documents),
builder: (context, futureSnap)
// Error/null handling
return ListView.builder(
shrinkWrap: true,
itemCount: futureSnap.data.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index)
//Continuing with populating
);
);
),
),
处理这样的流程的最佳方法是什么?创建一个方法来修改 Firestore 流中的数据,然后在根本不需要 ListView.builder 的情况下返回?
编辑:我尝试像这样创建自己的流:
Stream<Map<String, dynamic>> aStream2() async*
QuerySnapshot snap = await Firestore.instance
.collection(FirstLevel)
.document(OWN UID)
.collection(SecondLevel)
.getDocuments();
for (var doc in snap.documents)
Map<String, dynamic> data = Map<String, dynamic>();
DocumentSnapshot userDoc = await Firestore.instance
.collection(FirstLevel)
.document(OTHER USERS UID RECEIVED FROM STREAM)
.get();
data['i'] = userDoc['i'];
yield data;
但是,将新 Document 添加到 SecondLevel 集合时不会触发/更新 Stream。
【问题讨论】:
您可以通过使用async*
和await for
从头开始创建流来做到这一点。你可以阅读更多关于这个here的信息。
谢谢。我确实尝试将流更改为自定义并为 StreamBuilder 生成修改后的结果,但是我遇到了在将文档添加到 Firestore 集合时没有触发它的问题(因为 StreamBuilder 是由 List 的流提供的从自定义流返回,而不是像我提供的示例中那样从 Firestore 本身返回)。我是不是看错了这个流程?
【参考方案1】:
好吧,我想我找到了解决方法。我从流中获取数据,对其进行修改,然后通过一种方法将其交给 StreamBuilder,不再需要 FutureBuilder。正如克里斯托弗摩尔在评论中提到的那样,关键是await for
。流方法如下所示:
Stream<List> aStream() async*
List dataToReturn = List();
Stream<QuerySnapshot> stream = Firestore.instance
.collection(LevelOne)
.document(OWN UID)
.collection(LevelTwo)
.snapshots();
await for (QuerySnapshot q in stream)
for (var doc in q.documents)
Map<String, dynamic> dataMap= Map<String, dynamic>();
DocumentSnapshot userDoc = await Firestore.instance
.collection('UserData')
.document(doc['other user data var'])
.get();
dataMap['i'] = userDoc['i'];
//...//
dataToReturn.add(dataMap);
yield dataToReturn;
然后 StreamBuilder 会根据我的需要填充修改后的数据。
【讨论】:
【参考方案2】:我发现自己使用它在我的应用程序中使用 Dash Chat 包来实现聊天系统。我认为在流上使用 map 函数可能会更干净,这里有一个示例:
Stream<List<ChatMessage>> getMessagesForConnection(
String connectionId)
return _db
.collection('connections')
.doc(connectionId)
.collection('messages')
.snapshots()
.map<List<ChatMessage>>((event)
List<ChatMessage> messages = [];
for (var doc in event.docs)
try
messages.add(ChatMessage.fromJson(doc.data()));
catch (e, stacktrace)
// do something with the error
return messages;
);
【讨论】:
以上是关于Flutter - 从 Stream 接收然后修改数据的主要内容,如果未能解决你的问题,请参考以下文章
Stream Builder 在 Flutter 中的先前数据之上更新数据
使用Provider for DI时如何根据Firebase Auth流修改Flutter Firebase Stream监听器?
使用 Stream 从 FireStore 获取数据并将其映射到 Flutter 类
从 Stream 检索快照时,Flutter/Firestore 返回类型 List<Review> 不是“Map<String, dynamic>”类型的子类型