You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter异步函数randomChat返回空值问题求助

Flutter异步函数randomChat返回空值问题排查与修复

调用randomChat异步函数时,返回结果为空,不符合预期逻辑。以下是相关代码及问题根源分析:

相关代码

randomChat函数

Future<String> randomChat(String userId) async {
  String roomId = await connectRoom(userId);
  return roomId;
}

connectRoom函数(问题核心所在)

Future<String> connectRoom(String userId) async {
  List<String> connectedUsers = await getChattingWith(userId);
  late String roomId;

  // 查找所有userId2为空的房间
  FirebaseFirestore.instance
      .collection('rooms')
      .where('userId2', isEqualTo: "")
      .where("userId1", isNotEqualTo: userId)
      .get()
      .then((snapshot) async {
    // 如果没找到空房间,创建新房间
    if (snapshot.docs.isEmpty) {
      print("call empty");
      String roomId = await createRoom(userId);
      return roomId;
    }

    // 查找未与当前用户连接的空房间并加入
    for (int i = 0; i < snapshot.docs.length; i++) {
      var data = snapshot.docs[i].data();
      Room room = Room.fromJson(data);
      // 检查该空房间是否已与当前用户连接
      bool found = connectedUsers.contains(room.userId1);

      if (!found) {
        FirebaseFirestore.instance
            .collection('rooms')
            .doc(room.id)
            .update({"userId2": userId});
        print("call not found = $roomId");
        return roomId = room.id;
      } else {
        
        roomId = await createRoom(userId);
        print("call found = $roomId");
        return roomId;
      }
    }
  });
  print("call nothing = $roomId");
  return roomId;
}

调用代码(打印结果为空)

onPressed: () async {
  String roomId = await randomChat(uid);
  print(roomId);
},

createRoom函数(可正常返回roomId)

Future<String> createRoom(String userId) async {
  DocumentReference docRef =
      await FirebaseFirestore.instance.collection("rooms").add({
    "userId1": userId,
    "userId2": "",
    "created_at": DateTime.now().toString(),
  });
  await docRef.update({"roomId": docRef.id});
  print("create room: ${docRef.id}");
  return docRef.id;
}

问题根源

connectRoom函数中混用了then回调和async/await,导致异步逻辑出现竞态:

  • 外层代码调用Firestore查询后,没有等待then回调执行完成,就直接执行到最后的print并返回roomId
  • 此时roomId虽声明为late,但并未被then回调中的逻辑赋值(then里的return只是回调函数的返回值,不会改变外层函数的返回结果)

修复方案

将then回调替换为await,统一使用async/await写法,确保函数等待Firestore操作完成后再返回结果:

Future<String> connectRoom(String userId) async {
  List<String> connectedUsers = await getChattingWith(userId);

  // 用await等待Firestore查询结果
  final snapshot = await FirebaseFirestore.instance
      .collection('rooms')
      .where('userId2', isEqualTo: "")
      .where("userId1", isNotEqualTo: userId)
      .get();

  // 无空房间则创建新房间
  if (snapshot.docs.isEmpty) {
    print("call empty");
    return await createRoom(userId);
  }

  // 遍历空房间,查找可加入的目标
  for (int i = 0; i < snapshot.docs.length; i++) {
    var data = snapshot.docs[i].data();
    Room room = Room.fromJson(data);
    bool found = connectedUsers.contains(room.userId1);

    if (!found) {
      // 等待房间更新完成再返回
      await FirebaseFirestore.instance
          .collection('rooms')
          .doc(room.id)
          .update({"userId2": userId});
      print("call not found = ${room.id}");
      return room.id;
    } else {
      final newRoomId = await createRoom(userId);
      print("call found = $newRoomId");
      return newRoomId;
    }
  }

  // 兜底逻辑:循环结束仍无结果则创建新房间
  final fallbackRoomId = await createRoom(userId);
  print("call fallback = $fallbackRoomId");
  return fallbackRoomId;
}

修复说明

  1. 移除then回调,用await等待异步操作完成,保证逻辑执行顺序
  2. 去掉不必要的late变量声明,直接通过return返回结果,避免未初始化风险
  3. 给Firestore的update操作添加await,确保房间状态更新完成后再返回ID
  4. 增加兜底逻辑,增强代码健壮性

内容的提问来源于stack exchange,提问作者cipano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 03:15:59