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

如何监听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: '',
    ),
  ),
);

关键注意事项

  1. Hive对象更新规则:修改ChatRoom内部的消息列表后,必须调用box.put()将对象重新存入Box,否则Hive的监听器不会触发。
  2. 精准监听优化:使用listenable(keys: [widget.userNumber])仅监听当前ChatRoom的变化,避免不必要的UI重建,提升性能。
  3. 接收消息处理:收到新消息时,同样需要找到对应ChatRoom,添加消息后调用box.put()同步到Hive,ChatScreen会自动更新UI。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 03:06:23