如何在map()(Flutter,Firestore)中使用异步代码

时间:2019-11-21 15:47:06

标签: firebase flutter dart google-cloud-firestore

我正在使用Flutter和Firestore插件开发群聊应用。从数据库中获取数据并将快照转换为“消息列表”非常正常。但是现在我想将数据库中的uid转换为用户名(uid及其用户名保存在db中)。这是我的代码:

final CollectionReference messagesCollection =
    Firestore.instance.collection('messages');

final CollectionReference usersCollection =
    Firestore.instance.collection('users');

Future<String> getUsernameByUID(String _uid) async {
  String username =
      await usersCollection.document(uid).get().then((querySnapshot) {
    return (querySnapshot.data["username"]);
  });
  return username;
}

List<Message> _messagesFromSnapshot(QuerySnapshot snapshot){
  return snapshot.documents.map((doc) {

    String username = await getUsernameByUID(doc.data["uid"]);

    return Message(
      text: doc.data["text"] ?? "",
      username: username ?? "",
      time: doc.data["time"] ?? "",
    );
  }).toList();
}


Stream<List<Message>> get messages {
  return messagesCollection
      .orderBy("time")
      .snapshots()
      .map(_messagesFromSnapshot);
}

问题出在这一行,因为我无法在map()内部运行此异步代码。

String username = await getUsernameByUID(doc.data["uid"]);

是否有解决此问题的解决方案?预先感谢。

2 个答案:

答案 0 :(得分:1)

您需要的是Future.forEach方法。它会遍历列表,并等待所有异步方法完成,然后再继续执行列表中的下一项。

Future<List<Message>> _messagesFromSnapshot(QuerySnapshot snapshot) async {
  List<Message> _messages = [];
  await Future.forEach(snapshot.documents, (doc) async {
    String username = await getUsernameByUID(doc.data["uid"]);
    _messages.add(
       Message(
        text: doc.data["text"] ?? "",
        username: username ?? "",
        time: doc.data["time"] ?? "",)
     );   
    });   
  return _messages; 
}

下面是一个示例dartpad

答案 1 :(得分:1)

async函数必须返回一个Future,因此在您的回调中添加async关键字意味着您的List.map()调用现在必须返回一个{{ 1}} s。

您可以使用Future.waitList转换为Future

List<Future<Message>>

当然,List<Message>返回Future<List<Message>> _messagesFromSnapshot(QuerySnapshot snapshot) async { var futures = snapshot.documents.map((doc) async { String username = await getUsernameByUID(doc.data["uid"]); return Message( text: doc.data["text"] ?? "", username: username ?? "", time: doc.data["time"] ?? "", ); }); return await Future.wait(futures); } ,并且必须进行Future.wait,因此现在Future也必须是await。异步具有传染性,因此会影响_messagesFromSnapshot的所有调用方。

由于async的getter返回_messagesFromSnapshot并且已经是异步的,因此我相信您可以使用Stream.asyncMap

messages