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
相关产品推荐
相关产品推荐

