【问题标题】:Flutter and ReceivePort: Bad state: Stream has already been listened toFlutter 和 ReceivePort:状态不佳:Stream 已被监听
【发布时间】:2021-03-06 07:04:39
【问题描述】:

我有一堂课,里面有这段代码:

class GeofenceManager {
  ReceivePort geofencingMessagePort = ReceivePort();

  Stream<String> get events {
    return geofencingMessagePort.map((event) => event.toString());
  }
  ...

在我的 UI 中,我有一个像这样的 StreamBuilder

  @override
  Widget build(BuildContext context) {
    super.build(context);
    var geofenceManager = Provider.of<GeofenceManager>(context);
    return StreamBuilder(
      initialData: "Waiting ...",
      stream: geofenceManager.events,
      ...

但它不起作用。当我运行应用程序时出现此错误:

Bad state: Stream has already been listened to.

UI 的第一次构建有效,但如果我触发了第二次构建,我会收到错误消息。我尝试过使用asBroadcastStream(),但并没有解决问题。

所以我有点卡住了,知道如何解决这个问题吗?

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    好的,通过添加StreamController 并监听端口而不是暴露它来让它工作。所以我的代码现在看起来像这样:

    class GeofenceManager {
      ReceivePort geofencingMessagePort = ReceivePort();
      StreamController<String> _eventController = StreamController<String>.broadcast();
      
      Stream<String> get events {
        return _eventController.stream;
      }
    
      GeofenceManager._() {
        IsolateNameServer.registerPortWithName(_geofencingMessagePort.sendPort, 'geofencing_send_port');
        _geofencingMessagePort.listen((message) {
          _eventController.add(message);
        });
      }
    
      ...
    

    这可行,但我不确定它是否是最佳解决方案。有什么想法吗?

    【讨论】:

      【解决方案2】:

      Stream.asBroadcastStream(..) 应该可以工作。确保不要多次调用geofencingMessagePort .asBroadcastStream(..),因为这会导致重新订阅单个订阅ReceivePort。见documentation

      返回的流将在添加第一个订阅者时订阅此流

      不幸的是,您不能像示例中那样使用 getter

      Stream<String> get events {
        return geofencingMessagePort.asBroadcastStream();
      }
      

      因为对events 的每次访问都会调用asBroadcastStream(),而asBroadcastStream() 又会尝试仅重新订阅单一订阅geofencingMessagePort

      相反,您可以将广播流分配给单独的字段:

      ReceivePort _geofencingMessagePort = ReceivePort();
      Stream<String> _eventController = _geofencingMessagePort.asBroadcastStream().map((event) => event.toString());
      Stream<String> get eventController => _eventController;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-04
        • 2018-09-01
        • 1970-01-01
        • 2020-03-08
        • 2021-03-30
        • 2021-02-17
        • 2021-06-04
        • 2020-05-22
        相关资源
        最近更新 更多