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

如何使用单个StreamController实现多页面的数据流共享监听?

问题解答

基础结论

可以仅通过原生StreamController实现跨页面共享Stream的需求,无需引入RxDart。

问题根源

你当前使用的普通广播流(BroadcastStream)默认不缓存历史事件,仅会将事件推送给订阅时已经处于监听状态的订阅者。你在仪表盘页面先完成初始化、拿到首帧数据推送到流之后,再进入其他页面订阅,自然拿不到之前已经发送过的最新数据。

解决方案

新增缓存变量存储最新的流数据,新订阅者加入时先返回缓存的最新值,再同步后续的流更新即可,修改后的单例代码如下:

class ChatFieldService {
  static final ChatFieldService _singleton = ChatFieldService._internal();
  factory ChatFieldService() => _singleton;
  ChatFieldService._internal();

  final FirebaseService db = FirebaseService();
  String fromUserId;
  // 新增缓存变量存储最新数据
  List<ChatFieldModel> _latestChatFields = [];
  final StreamController<List<ChatFieldModel>> _chatFields$ = StreamController<List<ChatFieldModel>>.broadcast();

  // 重写流获取逻辑:新订阅者先拿到缓存的最新数据,再接收后续更新
  Stream<List<ChatFieldModel>> get getChatFields async* {
    yield _latestChatFields;
    yield* _chatFields$.stream;
  }

  StreamSubscription streamSubscription;

  void initialize(String id) {
    // 防止同用户重复初始化
    if (fromUserId == id) return;
    fromUserId = id;
    _getAllChatFields();
  }

  // 注意:该方法不要在单个页面销毁时调用,仅在用户登出、APP全局销毁时调用
  void dispose() {
    streamSubscription?.cancel();
    _chatFields$?.close();
    _latestChatFields = [];
    fromUserId = null;
  }

  void _getAllChatFields() {
    // 先取消旧的订阅避免重复监听
    streamSubscription?.cancel();
    streamSubscription = db.getAllChatField(fromUserId).listen((data) {
      // 先更新缓存再推送事件
      _latestChatFields = data;
      if (!_chatFields$.isClosed) _chatFields$.sink.add(data);
    });
  }
}

额外注意事项

  • 每个页面自己创建的StreamSubscription,需要在当前页面的dispose生命周期中取消,避免内存泄漏:
@override
void dispose() {
  oneSubscription?.cancel();
  super.dispose();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 15:45:00