【问题标题】:Flutter: Stream has already been listened to [duplicate]颤振:流已经被收听[重复]
【发布时间】:2019-05-19 09:15:33
【问题描述】:

我正在使用 BLoC 从 Firestore 加载我的预设对象。这是我的 Bloc 模型:

class StatisticsBloc extends BlocBase {

  List<Preset> _presets;

  StreamController<List<Preset>> _presetsController = new StreamController();

  Stream<List<Preset>> get getPresets => _presetsController.stream.asBroadcastStream();

  StatisticsBloc() {
    print('init Statistics Bloc');
    _presets = [];
    Firestore.instance.collection('Presets').snapshots().asBroadcastStream().listen(_onPresetsLoaded);
  }

  @override
  void dispose() {
    print('Disposed Statistics Bloc');
    _presetsController.close();
  }

  void _onPresetsLoaded(QuerySnapshot data) {
    _presets = [];
    data.documents.forEach((DocumentSnapshot snap) {
      Preset preset = Preset.fromDoc(snap);
      _presets.add(preset);
    });
    _presetsController.sink.add(_presets);
  }
}

然后我像这样显示列表:

class StatisticsPage extends StatelessWidget {

  StatisticsPage() {
    print('Created StatisticsPage');
  }

  @override
  Widget build(BuildContext context) {
    final StatisticsBloc statisticsBloc = BlocProvider.of<StatisticsBloc>(context);
    final List<Preset> _ = [];

    print(statisticsBloc.getPresets.isBroadcast);

    return Scaffold(
      appBar: AppBar(
        title: Text('Statistics'),
      ),
      body: StreamBuilder(
        stream: statisticsBloc.getPresets,
        initialData: _,
        builder: (BuildContext context, AsyncSnapshot<List<Preset>> snapshot) {
          if (snapshot.hasData) {
            return ListView(
              children: snapshot.data.map((Preset preset) {
                print(preset.name);
                return new ListTile(
                  title: new Text(preset.name),
                  subtitle: new Text(preset.id),
                );
              }).toList(),
            );
          } else {
            Text('No Data');
            print('No Data');
          }
        }
      )
    );
  }
}

问题是,我在标签栏中显示StatisticsPage,所以当我切换标签并返回它时,它将被构建多次。在第一次访问时它可以工作,但是当我切换选项卡并返回它时,小部件会重建并且我收到错误:Bad state: Stream has already been listened to.。正如您在StatisitcsBloc 中看到的那样,我尝试将getPresets 流声明为广播流,但这不起作用。

还有一个第二个问题:有没有更好的方法将我从 Firestore 获得的 Stream&lt;QuerySnapshot&gt; 转换为 Stream&lt;List&lt;Presets&gt;&gt;

【问题讨论】:

标签: firebase dart flutter


【解决方案1】:

很简单,从RxDart libraryBehaviorSubject class

BehaviorSubject 默认是一个广播(又名热)控制器,以履行 Rx Subject 合约。这意味着可以多次收听主题的流。

所以,换行

StreamController<List<Preset>> _presetsController = new StreamController();

StreamController<List<Preset>> _presetsController = new BehaviorSubject();

全部删除

.asBroadcastStream()

就是这样!

在官方文档中是not recommended to use asBroadcastStream()

创建流控制器的一种更危险的方法是通过 asBroadcastStream() 查看单订阅控制器。调用 asBroadcastStream 基本上是告诉单订阅流用户想要接管流的生命周期管理。结合 cancelOnError 订阅者,这很容易导致永远不会关闭的单流订阅,从而导致内存或资源泄漏。

【讨论】:

  • 它有帮助,但你忘了提到这个答案需要 RxDart 库
  • 这个答案拯救我的一天谢谢
猜你喜欢
  • 2018-12-26
  • 2020-01-13
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 2023-02-16
  • 2021-12-26
  • 2023-03-29
  • 2021-05-25
相关资源
最近更新 更多