Flutter StreamController返回重复数据

时间:2019-06-20 01:16:41

标签: flutter dart

我在以下层次结构中设置了小部件,以便在两个标签之间传递数据

DataShareWidget
 TabBarView
   InputManagment
   InfiniteListView

DataShareWidget扩展了InheritedWidget并包含ShareData类,该类具有一个StreamController来发送和接收数据。

但是在接收端(InfiniteListView选项卡)正在获取重复数据。

在进入流之前,我已经从InputManagment中打印出原始数据,但是似乎没有任何重复的数据,因此流中一定有东西。

这是主文件中的相关代码

class ShareData {
  final StreamController _streamController = StreamController.broadcast();
  Stream get stream => _streamController.stream;
  Sink get sink => _streamController.sink;
}

class DataShareWidget extends InheritedWidget {
  final ShareData data;
  DataShareWidget({
    Key key,
    @required Widget child,
  }) :assert(child != null),
      data = ShareData(),
      super(key: key, child: child);
  static ShareData of (BuildContext context) => (context.inheritFromWidgetOfExactType(DataShareWidget) as DataShareWidget).data;
  @override
  bool updateShouldNotify(DataShareWidget old) => false;
}

@override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("MyApp"),
        bottom: TabBar(
          tabs: Tabs,
          controller: _tabController,
        ),
      ),
      body: DataShareWidget(
        child: TabBarView(
          controller: _tabController,
          children: [
            InputManagment(),
            InfiniteListView(),
          ],
        ),
      ),
    );
  }

在数据管理文件中,我有这行代码来添加数据

DataShareWidget.of(context).sink.add(inputData);

这是InfiniteListView的代码

class _InfiniteScrollListViewState extends State<InfiniteScrollListView> with AutomaticKeepAliveClientMixin<InfiniteScrollListView>{
  @override
  bool get wantKeepAlive => true;

  ScrollController _scrollController = ScrollController();

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  var _listViewData = new List();

  _dataFormat(data){
    var time = DateFormat('kk:mm:ss').format(DateTime.now());
    var timeStampedData = time.toString() + "| " + data;
    setState(() {_listViewData.add(timeStampedData); });
  }

  @override
  Widget build(BuildContext context) {
    DataShareWidget.of(context).stream.listen((data) => _dataFormat(data));
    return ListView.builder(
        itemCount: _listViewData.length,
        controller: _scrollController,
        itemBuilder: (context, index) {
          return ListTile(
            title: AutoSizeText(_listViewData[index], maxLines: 2),
            dense: true,
          );
        },
      );
  }
}

编辑:根据@jamesdlin的建议,我已经使用StreamBuilder重构了代码,并且看来已经解决了问题,这是下面的更新代码。

_dataFormat(data){
    var time = DateFormat('kk:mm:ss').format(DateTime.now());
    var timeStampedData = time.toString() + "| " + data;
    _listViewData.add(timeStampedData);
  }

  @override
  Widget build(BuildContext context) {
    //_scrollToBottom();
    return StreamBuilder(
      stream: DataShareWidget.of(context).stream,
      builder: (BuildContext context, AsyncSnapshot snapshot){
        if(snapshot.hasError){ return Text(snapshot.error);}
        if(snapshot.hasData){
          _dataFormat(snapshot.data);
          return ListView.builder(
            itemCount: _listViewData.length,
            controller: _scrollController,
            itemBuilder: (context, index) {
              return ListTile(
                title: AutoSizeText(_listViewData[index], maxLines: 2),
                dense: true,
              );
            },
          );
        }
      }
    );

1 个答案:

答案 0 :(得分:0)

每次调用listen时,您都会在Stream上调用_InfiniteScrollListViewState.build。这将导致您的回调被多次调用。您应该只听一次Stream

您也许还应该考虑使用StreamBuilder小部件。