【问题标题】:Flutter - Receive and then modify data from StreamFlutter - 从 Stream 接收然后修改数据
【发布时间】:2020-11-14 12:51:57
【问题描述】:

我正在尝试执行以下操作:

  1. 监听 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 本身返回)。我是不是看错了这个流程?

标签: firebase flutter google-cloud-firestore stream-builder


【解决方案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;
    });}
    

    【讨论】:

      猜你喜欢
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多