Dart/Flutter - 回调函数中的"yield"

26
我需要为一个函数生成一个列表;然而,我希望从回调函数中生成列表,而此回调函数位于主函数内部 - 这会导致yield语句不会在主函数中执行,而是在回调函数中执行。我的问题与此处解决的问题非常相似:Dart Component: How to return result of asynchronous callback? ,但由于我需要使用yield而不是return,因此无法使用Completer。下面的代码应该更好地描述了这个问题:
Stream<List<EventModel>> fetchEvents() async* { //function [1]
    Firestore.instance
        .collection('events')
        .getDocuments()
        .asStream()
        .listen((snapshot) async* { //function [2]
      List<EventModel> list = List();
      snapshot.documents.forEach((document) {
        list.add(EventModel.fromJson(document.data));
      });

      yield list; //This is where my problem lies - I need to yield for function [1] not [2]
    });
  }
2个回答

32

你可以使用await for来处理外部函数中的事件,而不是使用处理另一个函数内事件的.listen

另外,当你在一个内部流回调中产生仍在填充的List实例时,你可能需要重新考虑这个模式...

Stream<List<EventModel>> fetchEvents() async* {
  final snapshots =
      Firestore.instance.collection('events').getDocuments().asStream();
  await for (final snapshot in snapshots) {
    // The `await .toList()` ensures the full list is ready
    // before yielding on the Stream
    final events = await snapshot.documents
        .map((document) => EventModel.fromJson(document.data))
        .toList();
    yield events;
  }
}

2
谢谢Nate,完美的答案。我不知道await for,但这解决了我的问题。 - Marcus Bornman
3
我该如何使用await进行实时更新? - Ekta Padaliya

0
我想在这里提出一个改进建议。建议的await for解决方案在某些情况下应该避免使用,因为它是不可取消的监听器,并且它永远不会停止监听,这可能会导致内存泄漏。您也可以使用.map来转换流产生的结果,如下所示(尚未尝试编译,但主要思路应该很清楚):
Stream<List<EventModel>> fetchEvents() { // remove the async*
    Firestore.instance
        .collection('events')
        .getDocuments()
        .asStream()
        .map((snapshot) { // use map instead of listen
      List<EventModel> list = List();
      snapshot.documents.forEach((document) {
        list.add(EventModel.fromJson(document.data));
      });

      return list; // use return instead of yield
    });
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接