如何在Flutter中基于ID从MQTT Broker获取并展示特定数据?
实现方案
1. 关于write函数的说明
不需要用write函数,write是MQTT客户端用来发布消息到Broker的方法,你当前场景是订阅接收数据,只需要处理订阅后的数据流即可。
2. 具体实现步骤
步骤1:定义数据模型
先把MQTT收到的消息解析成带ID的实体类,方便后续筛选和展示:
import 'dart:convert'; import 'package:mqtt_client/mqtt_client.dart'; class DeviceData { final String id; final String value; // 可根据实际数据类型调整为int、double等 DeviceData({required this.id, required this.value}); // 从MQTT消息负载解析成DeviceData对象 static DeviceData? fromMqttMessage(MqttReceivedMessage<MqttMessage> message) { final payload = MqttPublishPayload.bytesToStringAsString( (message.payload as MqttPublishMessage).payload.message); // 假设消息格式为JSON:{"id": "sensor_01", "value": "26.3"} try { final jsonData = jsonDecode(payload); return DeviceData( id: jsonData['id'], value: jsonData['value'].toString(), ); } catch (e) { print('消息解析失败: $e'); return null; } } }
步骤2:在页面中处理MQTT数据流并维护状态
用StatefulWidget管理订阅和数据状态,监听MQTT的updates流,过滤出你需要的特定ID数据:
import 'package:flutter/material.dart'; import 'package:mqtt_client/mqtt_client.dart'; class MqttCardPage extends StatefulWidget { const MqttCardPage({super.key}); @override State<MqttCardPage> createState() => _MqttCardPageState(); } class _MqttCardPageState extends State<MqttCardPage> { StreamSubscription? _mqttSubscription; DeviceData? _targetDeviceData; final String _targetId = 'sensor_01'; // 你要展示的目标设备ID @override void initState() { super.initState(); _startMqttSubscription(); } Future<void> _startMqttSubscription() async { // 调用你已实现的mqttSubscribe方法订阅主题 final updatesStream = await mqttSubscribe(topic: 'your/device/topic'); if (updatesStream != null) { _mqttSubscription = updatesStream.listen((List<MqttReceivedMessage<MqttMessage>> messages) { for (final message in messages) { final deviceData = DeviceData.fromMqttMessage(message); // 筛选出目标ID的数据并更新UI if (deviceData != null && deviceData.id == _targetId) { setState(() { _targetDeviceData = deviceData; }); } } }); } } @override void dispose() { _mqttSubscription?.cancel(); client.disconnect(); // 页面销毁时断开MQTT连接 super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('设备数据展示')), body: Center( child: _targetDeviceData != null ? Card( elevation: 4, margin: const EdgeInsets.symmetric(horizontal: 16), child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( '设备ID: ${_targetDeviceData!.id}', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 12), Text( '当前数值: ${_targetDeviceData!.value}', style: const TextStyle(fontSize: 16), ), ], ), ), ) : const Text('等待数据推送...'), ), ); } }
步骤3:扩展支持多个特定ID的情况
如果需要展示多个设备的数据,可以用Map存储多个ID对应的数据,再遍历生成Card:
// 替换状态变量 Map<String, DeviceData> _deviceDataMap = {}; final List<String> _targetIds = ['sensor_01', 'sensor_02', 'sensor_03']; // 监听流时更新Map _mqttSubscription = updatesStream.listen((messages) { for (final message in messages) { final deviceData = DeviceData.fromMqttMessage(message); if (deviceData != null && _targetIds.contains(deviceData.id)) { setState(() { _deviceDataMap[deviceData.id] = deviceData; }); } } }); // 构建UI时生成多个Card @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('多设备数据展示')), body: ListView.builder( padding: const EdgeInsets.all(16), itemCount: _targetIds.length, itemBuilder: (context, index) { final id = _targetIds[index]; final data = _deviceDataMap[id]; return Card( elevation: 4, margin: const EdgeInsets.only(bottom: 12), child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text('设备ID: $id', style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), const SizedBox(height: 12), Text(data != null ? '当前数值: ${data.value}' : '暂无数据', style: const TextStyle(fontSize: 16)), ], ), ), ); }, ), ); }
3. 注意事项
- 确保MQTT消息格式可解析,如果不是JSON格式,调整
fromMqttMessage里的解析逻辑即可。 - 页面销毁时必须取消流订阅并断开MQTT连接,避免内存泄漏。
- 如果需要跨页面共享数据,可结合Provider、Riverpod等状态管理库优化。
内容的提问来源于stack exchange,提问作者syaf_
相关产品推荐
相关产品推荐

