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

Flutter:如何在ListView.builder中调用异步函数获取聊天用户名称?

解决方案

原代码问题分析

  • 初始错误代码:itemBuilder是同步回调,无法直接使用await调用异步函数
  • 尝试代码的问题:把FutureBuilder放在ListView外层,无法为每个聊天项单独获取用户名;未正确引用job变量;未从snapshot中提取数据;waiting状态未返回组件

正确实现方式

将FutureBuilder嵌套在每个ListTile内部,为每个聊天项单独异步获取对方用户名:

typedef JobCallback = void Function(CloudChat job);

class ChatsListWidget extends StatelessWidget {
  final Iterable<CloudChat> cloudChats;
  final JobCallback onDeleteJob;
  final JobCallback onTap;
  String get userId => AuthService.firebase().currentUser!.id;

  const ChatsListWidget({
    Key? key,
    required this.cloudChats,
    required this.onDeleteJob,
    required this.onTap,
  }) : super(key: key);

  // 优化获取对方用户ID的逻辑,增加空安全处理
  Future<String?> getOtherUsersName(List<String> userIdsArr) async {
    try {
      final otherUserInChatId = userIdsArr.firstWhere(
        (_userId) => _userId != userId,
        orElse: () => '',
      );
      
      if (otherUserInChatId.isEmpty) return null;

      final userData = await FirebaseFirestore.instance
          .collection('user')
          .doc(otherUserInChatId)
          .get();

      return userData.data()?[userFirstNameColumn];
    } catch (e) {
      // 处理异常,比如用户不存在的情况
      return '未知用户';
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: cloudChats.length,
      itemBuilder: (context, index) {
        final chat = cloudChats.elementAt(index);
        return ListTile(
          onTap: () => onTap(chat),
          title: FutureBuilder<String?>(
            // 为当前聊天项绑定对应的异步请求
            future: getOtherUsersName(chat.userIdsArr),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                // 加载中显示占位符
                return const Text('加载中...');
              } else if (snapshot.hasData && snapshot.data != null) {
                // 成功获取到用户名
                return Text(
                  snapshot.data!,
                  maxLines: 1,
                  softWrap: true,
                  overflow: TextOverflow.ellipsis,
                );
              } else {
                // 无数据或异常情况
                return const Text('未知用户');
              }
            },
          ),
          trailing: IconButton(
            onPressed: () => onDeleteJob(chat),
            icon: const Icon(Icons.delete),
          ),
        );
      },
    );
  }
}

性能优化建议

上述方案每个聊天项都会发起一次Firestore请求,当列表数据较多时会影响性能。可以改为批量预加载所有对方用户的信息:

typedef JobCallback = void Function(CloudChat job);

class ChatsListWidget extends StatefulWidget {
  final Iterable<CloudChat> cloudChats;
  final JobCallback onDeleteJob;
  final JobCallback onTap;

  const ChatsListWidget({
    Key? key,
    required this.cloudChats,
    required this.onDeleteJob,
    required this.onTap,
  }) : super(key: key);

  @override
  State<ChatsListWidget> createState() => _ChatsListWidgetState();
}

class _ChatsListWidgetState extends State<ChatsListWidget> {
  late Future<Map<String, String>> _userNamesFuture;
  String get userId => AuthService.firebase().currentUser!.id;

  @override
  void initState() {
    super.initState();
    _userNamesFuture = _preloadUserNames();
  }

  // 批量预加载所有需要的用户名
  Future<Map<String, String>> _preloadUserNames() async {
    // 提取所有需要查询的对方用户ID(去重)
    final userIds = widget.cloudChats
        .map((chat) => chat.userIdsArr.firstWhere((id) => id != userId))
        .toSet()
        .toList();

    if (userIds.isEmpty) return {};

    // 批量查询用户信息
    final batchSnapshot = await FirebaseFirestore.instance
        .collection('user')
        .where(FieldPath.documentId, whereIn: userIds)
        .get();

    return {
      for (var doc in batchSnapshot.docs)
        doc.id: doc.data()[userFirstNameColumn] ?? '未知用户'
    };
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Map<String, String>>(
      future: _userNamesFuture,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        } else if (snapshot.hasData) {
          final userNames = snapshot.data!;
          return ListView.builder(
            itemCount: widget.cloudChats.length,
            itemBuilder: (context, index) {
              final chat = widget.cloudChats.elementAt(index);
              final otherUserId = chat.userIdsArr.firstWhere((id) => id != userId);
              final userName = userNames[otherUserId] ?? '未知用户';
              
              return ListTile(
                onTap: () => widget.onTap(chat),
                title: Text(
                  userName,
                  maxLines: 1,
                  softWrap: true,
                  overflow: TextOverflow.ellipsis,
                ),
                trailing: IconButton(
                  onPressed: () => widget.onDeleteJob(chat),
                  icon: const Icon(Icons.delete),
                ),
              );
            },
          );
        } else {
          return const Center(child: Text('加载失败'));
        }
      },
    );
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:01:06