0

当我使用BottomNavigationBarBLoC 模式时,会导致错误,Bad state: Stream has already been listened to.

我可能只在一个地方收听 BLoC 的流。

我的代码如下。

主要.dart

import 'package:flutter/material.dart';
import 'package:bottom_tab_bloc/app_state_bloc.dart';
import 'package:bloc_provider/bloc_provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      creator: (context, _bag) => AppStateBloc(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(title: 'Flutter Demo Home Page'),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String activeTab = "tab1";
  final bottomTabs = ["tab1", "tab2"];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(activeTab),
      ),
      body: buildTab(activeTab),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: bottomTabs.indexOf(activeTab),
        onTap: (int index) {
          setState(() {
            activeTab = bottomTabs[index];
          });
        },
        items: bottomTabs.map((tab) =>
          buildBnbItem(tab)
        ).toList(),
      ),
    );
  }

  Widget buildTab(String tab) {
    if (tab == "tab1") {
      return TabOne();
    } else if (tab == "tab2") {
      return TabTwo();
    }
  }

  BottomNavigationBarItem buildBnbItem (String tab) {
    assert(bottomTabs.contains(tab));

    if (tab == "tab1") {
      return BottomNavigationBarItem(
        title: Text('Tab1'),
        icon: Icon(Icons.looks_one),
      );
    } else if (tab == "tab2") {
      return BottomNavigationBarItem(
        title: Text('Tab1'),
        icon: Icon(Icons.looks_two),
      );
    }
  }
}

class TabOne extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AppStateBloc bloc = BlocProvider.of<AppStateBloc>(context);
    return StreamBuilder(
      stream: bloc.outValue1,
      builder: (context, snapshot) =>
        Center(child: Text(snapshot.data.toString())),
    );
  }
}

class TabTwo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final AppStateBloc bloc = BlocProvider.of<AppStateBloc>(context);
    return StreamBuilder(
      stream: bloc.outValue2,
      builder: (context, snapshot) =>
        Center(child: Text(snapshot.data.toString())),
    );
  }
}

app_state_bloc.dart

import 'dart:async';
import 'package:bloc_provider/bloc_provider.dart';

class AppStateBloc implements Bloc {
  StreamController<int> _value1Controller
    = StreamController<int>();
  Sink<int> get _inValue1 => _value1Controller.sink;
  Stream<int> get outValue1 => _value1Controller.stream;

  StreamController<int> _updateValue1Controller
    = StreamController<int>();
  Sink<int> get updateValue1 =>
      _updateValue1Controller.sink;

  StreamController<int> _value2Controller
  = StreamController<int>();
  Sink<int> get _inValue2 => _value2Controller.sink;
  Stream<int> get outValue2 => _value2Controller.stream;

  StreamController<int> _updateValue2Controller
  = StreamController<int>();
  Sink<int> get updateValue2 =>
      _updateValue2Controller.sink;

  AppStateBloc(){
    _inValue1.add(1);
    _updateValue1Controller.stream.listen(_updateValue1);
    _inValue2.add(2);
    _updateValue2Controller.stream.listen(_updateValue2);
  }

  @override
  void dispose() {
    _value1Controller.close();
    _updateValue1Controller.close();
    _value2Controller.close();
    _updateValue2Controller.close();
  }

  void _updateValue1(int value1) {
    _inValue1.add(value1);
  }

  void _updateValue2(int value2) {
    _inValue2.add(value2);
  }
}

我只能在第一次去TabTwofrom TabOne,但是当我回到TabOne.

我也尝试过使用StreamController<int>.broadcast()in app_state_bloc.dart,但snapshot.data总是null.

  • 如何BottomNavigationBar使用 BLoC 模式实现?
  • 为什么流被调用两次以上,尽管我只在一个地方写了每个流?
  • AppStateBloc.dispose()在这段代码中调用的吗?何时何地AppStateBloc.dispose()被调用?
  • 为什么广播流snapshot.data总是为空?
4

1 回答 1

2

为什么流被调用两次以上,尽管我只在一个地方写了每个流?

该错误与流的订阅者数量有关。StreamController默认情况下只允许一个订阅者。这就是为什么TabOne第一次工作正常,但后来中断的原因。

这段代码中是否调用了 AppStateBloc.dispose()?何时何地调用 AppStateBloc.dispose()?

当小部件被删除时会调用它BlocProvider,但由于它被用作应用程序根,我猜这只会在应用程序关闭时发生。

为什么广播流的 snapshot.data 总是为空?

没有侦听器时,广播流不会缓冲事件。由于您在TabOne创建之前写入流,因此事件丢失并且您得到null.

如何使用 BLoC 模式实现 BottomNavigationBar?

我想这取决于你的用例,但对于这个特定的例子,如果你StreamControllerrxdartBehaviorSubject替换,它工作正常,因为你会有一个总是向你发送最后一个事件的广播流。

于 2018-12-25T19:14:18.397 回答