如何在SignalR事件触发时同步更新Widget中的数据?
问题:SignalR WebSocket数据更新后Widget无法即时刷新
- 使用SignalR包通过WebSocket获取数据,新事件数据已存入
List,但Widget无法自动更新显示,需手动刷新页面 - 尝试用
Stream.periodic实现自动更新,但会导致事件中的图片闪烁,不符合需求 - 限制条件:只能使用SignalR库进行WebSocket通信
解决方案:用StreamController主动推送更新
核心思路是抛弃定时轮询的Stream.periodic,改用StreamController在SignalR事件触发时主动推送新数据,只有当真正有新数据时才触发Widget刷新,避免图片闪烁。
步骤1:重构SignalR连接逻辑,添加StreamController
替换原来的全局列表和轮询流,改用StreamController管理数据流:
// 全局或页面级的StreamController,用broadcast支持多Widget订阅 final _wantedStreamController = StreamController<List>.broadcast(); List _wanted = []; Future<void> initSignalRConnection() async { final httpConnectionOptions = HttpConnectionOptions( accessTokenFactory: () => SharedPreferenceService().loginWithToken(), skipNegotiation: true, transport: HttpTransportType.WebSockets); final hubConnection = HubConnectionBuilder() .withUrl( 'http://websockets/sockets', options: httpConnectionOptions, ) .build(); await hubConnection.start(); hubConnection.on('Wanted', (arguments) { // 原有音频逻辑保留 Future.delayed(const Duration(seconds: 7)) .then((value) => alarmplayer.StopAlarm()); alarmplayer.Alarm(url: 'assets/wanted.mp3', volume: 0.25); // 更新本地数据并主动推送到流中 _wanted = arguments as List; _wantedStreamController.add(_wanted); }); hubConnection.onclose(({error}) { // 连接关闭时推送错误,也可添加重连逻辑 _wantedStreamController.addError(Exception(error)); }); } // 对外暴露数据流 Stream<List> get wantedStream => _wantedStreamController.stream; // 页面销毁时务必关闭控制器,防止内存泄漏 void disposeSignalRResources() { _wantedStreamController.close(); }
步骤2:用StreamBuilder监听数据流更新Widget
在Widget中通过StreamBuilder监听wantedStream,实现数据更新时自动刷新UI:
StreamBuilder<List>( stream: wantedStream, initialData: [], // 设置初始空数据,避免加载状态闪烁 builder: (context, snapshot) { if (snapshot.hasError) { return Center(child: Text('连接出错: ${snapshot.error}')); } final dataList = snapshot.data!; // 这里替换成你的业务Widget,比如展示图片和数据的列表 return ListView.builder( itemCount: dataList.length, itemBuilder: (context, index) { final item = dataList[index]; return ListTile( leading: item['imageUrl'] != null ? Image.network(item['imageUrl'], fit: BoxFit.cover) : const Icon(Icons.image_not_supported), title: Text(item['title'] ?? '无标题'), subtitle: Text(item['description'] ?? ''), ); }, ); }, )
方案优势
- 仅在SignalR收到新
Wanted事件时推送数据,触发Widget刷新,彻底解决Stream.periodic轮询导致的重复刷新和图片闪烁问题 StreamController.broadcast()支持多个Widget同时监听数据流,适配多场景需求- 本地
_wanted列表始终保持最新,流推送确保UI与数据即时同步
内容的提问来源于stack exchange,提问作者user16357470
相关产品推荐
相关产品推荐

