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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:50:27