如何监听Hive Box中ChatRoom内ChatMessage列表的变化?
解决方案:监听Hive中ChatRoom内消息列表的变化
核心思路是让ChatScreen直接绑定Hive中的ChatRoom数据源,而非传递本地列表副本,这样当ChatRoom内的消息列表更新时,通过Hive的监听机制自动触发UI重建。
步骤1:调整ChatScreen参数
移除listOfmessages参数,仅保留ChatRoom的唯一标识(这里用userNumber作为ChatRoom的name):
class ChatScreen extends StatefulWidget { ChatScreen({ required this.userNumber, required this.server, Key? key, }) : super(key: key); String userNumber; String server; @override State<ChatScreen> createState() => _ChatScreenState(); }
步骤2:在ChatScreen中监听Hive Box
使用ValueListenableBuilder监听ChatRooms Box的变化,精准定位当前聊天对应的ChatRoom:
class _ChatScreenState extends State<ChatScreen> { final _textController = TextEditingController(); final String toNumber = 'remoteAddress'; @override void dispose() { _textController.dispose(); super.dispose(); } // 根据userNumber获取对应的ChatRoom,不存在则创建空实例 ChatRoom _getChatRoom(Box<ChatRoom> box) { return box.values.firstWhere( (chatRoom) => chatRoom.name == widget.userNumber, orElse: () => ChatRoom(name: widget.userNumber, chatmessage: []), ); } @override Widget build(BuildContext context) { double width = MediaQuery.of(context).size.width; double height = MediaQuery.of(context).size.height; return Scaffold( backgroundColor: Colors.black, appBar: AppBar( actions: [ IconButton( onPressed: () => print('add contact'), icon: Image.asset('assets/images/ic_add_contact_holo_dark.png'), ) ], title: const Text('Tel'), backgroundColor: Colors.grey[900], ), body: ChangeNotifierProvider( create: (_) => MessageService(), child: Column( children: [ // 顶部联系人信息栏(保留原有代码) Container( color: Colors.grey[800], child: Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 10, bottom: 5), child: Text( widget.userNumber, style: customTextStyle(18), ), ), Padding( padding: EdgeInsets.only(left: width / 39.2), child: Text( 'sip: ' + widget.userNumber + '@' + widget.server, style: const TextStyle(color: Colors.white), ), ), ], ), const Spacer(), Padding( padding: const EdgeInsets.only(bottom: 5), child: authStateWidget( context, '7221', widget.server, '', width, height, ), ), ], ), ), // 监听ChatRooms Box,仅关注当前ChatRoom的变化 ValueListenableBuilder<Box<ChatRoom>>( valueListenable: Hive.box<ChatRoom>('ChatRooms').listenable(keys: [widget.userNumber]), builder: (context, box, _) { final chatRoom = _getChatRoom(box); final messages = chatRoom.chatmessage; return Expanded( child: ListView.builder( shrinkWrap: true, reverse: true, // 最新消息显示在底部 itemCount: messages.length, itemBuilder: (context, index) { final msg = messages[index]; return ListTile( title: Text( msg.message, style: TextStyle(color: msg.isSender ? Colors.blue : Colors.green), ), subtitle: Text(msg.time), ); }, ), ); }, ), IconButton( onPressed: () => Navigator.of(context).pop(), icon: const Icon(Icons.arrow_back), ), // 消息输入栏(修改发送逻辑) Container( decoration: BoxDecoration(color: Colors.grey[900]), child: Padding( padding: const EdgeInsets.only(left: 5, right: 5), child: Row( children: [ SizedBox( width: width / 1.35, child: Padding( padding: EdgeInsets.only( bottom: height / 40.1, left: width / 39.2, ), child: TextField( style: const TextStyle(color: Colors.white), controller: _textController, decoration: const InputDecoration( hintText: 'Type to compose', hintStyle: TextStyle(fontSize: 14.0, color: Colors.white), enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.white), borderRadius: BorderRadius.only(bottomRight: Radius.zero), ), ), ), ), ), SizedBox(width: width / 39.2), Expanded( child: SizedBox( width: width / 4.9, child: ElevatedButton( onPressed: () async { final box = Hive.box<ChatRoom>('ChatRooms'); final chatRoom = _getChatRoom(box); // 创建新消息 final newMsg = ChatMessage( name: widget.userNumber, message: _textController.text, time: DateFormat('yyyy-MM-dd – kk:mm').format(DateTime.now()), isSender: true, deliverStatus: 'sending..', ); // 更新ChatRoom的消息列表并同步到Hive chatRoom.chatmessage.add(newMsg); await box.put(widget.userNumber, chatRoom); // 调用服务发送消息 await MessageService().writeOutcomingMessage( newMsg, <String, String>{ toNumber: widget.userNumber, message: _textController.text, }, ); _textController.clear(); }, child: const Text( 'Send', style: TextStyle(fontSize: 16, color: Colors.white), ), ), ), ), ], ), ), ), ], ), ), ); } }
步骤3:调整列表页跳转逻辑
不再传递消息列表,仅传递ChatRoom的标识:
Navigator.push( context, MaterialPageRoute( builder: (context) => ChatScreen( userNumber: chatName, server: '', ), ), );
关键注意事项
- Hive对象更新规则:修改ChatRoom内部的消息列表后,必须调用
box.put()将对象重新存入Box,否则Hive的监听器不会触发。 - 精准监听优化:使用
listenable(keys: [widget.userNumber])仅监听当前ChatRoom的变化,避免不必要的UI重建,提升性能。 - 接收消息处理:收到新消息时,同样需要找到对应ChatRoom,添加消息后调用
box.put()同步到Hive,ChatScreen会自动更新UI。
内容的提问来源于stack exchange,提问作者user17740770
相关产品推荐
相关产品推荐

