首页 > 解决方案 > 已从 BottomNavigationBar 项中侦听流

问题描述

在我的项目中,我正在使用带有自定义提供程序的架构。

class BlocProvider<T extends BlocBase> extends StatefulWidget {
  BlocProvider(
      {@required this.child,
      @required this.bloc,
      @required this.blocContext,
      Key key})
      : super(key: key);

  final T bloc;
  final Widget child;
  final BlocContextBase<T> blocContext;

  @override
  _BlocProviderState<T> createState() => _BlocProviderState<T>();

  static T of<T extends BlocBase>(BuildContext context) {
    final BlocProvider<T> provider = context.findAncestorWidgetOfExactType();
    return provider.bloc;
  }
}

class _BlocProviderState<T> extends State<BlocProvider<BlocBase>> {
  @override
  void initState() {
    super.initState();
    widget.blocContext.subscribe(widget.bloc, context);
  }

  @override
  void dispose() {
    widget.bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

在我切换到 BottomNavigationBar 之前,一切都运行良好。

class TabContainerContent {
  final Widget firstTab;
  final Widget secondTab;
  final Widget thirdTab;

  TabContainerContent(
      {@required this.firstTab,
      @required this.secondTab,
      @required this.thirdTab});
}

class TabContainerScreen extends StatefulWidget {
  final TabContainerContent _content;

  TabContainerScreen({@required TabContainerContent content})
      : _content = content;

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

class _TabContainerScreenState extends State<TabContainerScreen> {
  int _selectedIndex = 0;
  List<BottomNavigationBarItem> _bottomBarItems = [];
  List<Widget> _tabWidgets = [];

  @override
  void initState() {
    super.initState();

    _tabWidgets.add(widget._content.firstTab);
    _bottomBarItems.add(
      BottomNavigationBarItem(
        icon: Icon(Icons.map),
        label: 'Profile',
      ),
    );

    _tabWidgets.add(widget._content.secondTab);
    _bottomBarItems.add(
      BottomNavigationBarItem(
        icon: Icon(Icons.location_city),
        label: 'Search',
      ),
    );

    _tabWidgets.add(widget._content.thirdTab);
    _bottomBarItems.add(
      BottomNavigationBarItem(
        icon: Icon(Icons.ac_unit),
        label: 'Ads',
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _tabWidgets[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        items: _bottomBarItems,
        currentIndex: _selectedIndex,
        onTap: (int value) {
          setState(() {
            _selectedIndex = value;
          });
        },
      ),
    );
  }
}

仅当该集团在我的集团中有一个流控制器并且我在我的小部件中使用 StreamBuilder 时,问题才会开始。如果我转到另一个选项卡然后返回。然后我得到错误流已经被收听。在我看来,我没有在某处删除一些数据。

这就是集团的样子。

class ProfileBloc extends IProfileBloc {
      final StreamController<User> _userControllerOne = StreamController<User>();
    
      Sink<User> get _inUserState => _userControllerOne.sink;
      Stream<User> get outUserState => _userControllerOne.stream;
    
      @override
      void dispose() {
        _userControllerOne.close();
        super.dispose();
      }
}

--

class SearchBloc extends ISearchBloc {
      final StreamController<User> _userControllerTwo = StreamController<User>();
    
      Sink<User> get _inUserState => _userControllerTwo.sink;
      Stream<User> get outUserState => _userControllerTwo.stream;
    
      @override
      void dispose() {
        _userControllerTwo.close();
        super.dispose();
      }
}

--

class AdsBloc extends IAdsBloc {
      final StreamController<User> _userControllerThree = StreamController<User>();
    
      Sink<User> get _inUserState => _userControllerThree.sink;
      Stream<User> get outUserState => _userControllerThree.stream;
    
      @override
      void dispose() {
        _userControllerThree.close();
        super.dispose();
      }
}

这就是我的 UI 的样子

class ProfileScreen extends StatefulWidget {
  ProfileScreen({Key key}) : super(key: key);

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

class _ProfileScreenState extends State<ProfileScreen> {
  IProfileBloc _bloc;

  @override
  void initState() {
    super.initState();
    _bloc = BlocProvider.of(context);
    _bloc.loadUser();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
      child: StreamBuilder(
        stream: _bloc.outUserState,
        builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
          return Container();
        },
      ),
    ));
  }
}

--

class SearchScreen extends StatefulWidget {
  SearchScreen({Key key}) : super(key: key);

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

class _SearchScreenState extends State<SearchScreen> {
  ISearchBloc _bloc;

  @override
  void initState() {
    super.initState();
    _bloc = BlocProvider.of(context);
    _bloc.loadUser();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
      child: StreamBuilder(
        stream: _bloc.outUserState,
        builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
          return Container();
        },
      ),
    ));
  }
}

--

class AdsScreen extends StatefulWidget {
  AdsScreen({Key key}) : super(key: key);

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

class _AdsScreenState extends State<AdsScreen> {
  IAdsBloc _bloc;

  @override
  void initState() {
    super.initState();
    _bloc = BlocProvider.of(context);
    _bloc.loadUser();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SafeArea(
      child: StreamBuilder(
        stream: _bloc.outUserState,
        builder: (BuildContext context, AsyncSnapshot<User> snapshot) {
          return Container();
        },
      ),
    ));
  }
}

我也用注射器。

class ApplicationAssembly {
  static final Injector injector = Injector('ApplicationAssemblyInjector');

  //----------------------------------------------------------------------------

  static void initialize() {
    _registerManagers();
    _registerBlocs();
    _registerModuleBuilders();
  }

  static void _registerManagers() {
  }

  static void _registerBlocs() {
    injector.map<IProfileBloc>((i) => ProfileBloc());
    injector.map<IAdsBloc>((i) => AdsBloc());
    injector.map<ISearchBloc>((i) => SearchBloc());
  }

  static void _registerModuleBuilders() {
//TAB BAR MODULES---------------------------------------------------------------
    injector.map<ProfileModuleBuilder>((i) => () {
          return BlocProvider(
              child: ProfileScreen(),
              bloc: i.get<IProfileBloc>(),
              blocContext: ProfileBlocContext());
        });
    injector.map<SearchModuleBuilder>((i) => () {
          return BlocProvider(
              child: SearchScreen(),
              bloc: i.get<ISearchBloc>(),
              blocContext: SearchBlocContext());
        });
    injector.map<AdsModuleBuilder>((i) => () {
          return BlocProvider(
              child: AdsScreen(),
              bloc: i.get<IAdsBloc>(),
              blocContext: AdsBlocContext());
        });
//------------------------------------------------------------------------------
//TAB BAR-----------------------------------------------------------------------
    injector.map<TabModuleBuilder>((i) => () {
          Widget profileTab = i.get<ProfileModuleBuilder>()();
          Widget searchTab = i.get<SearchModuleBuilder>()();
          Widget adsTab = i.get<AdsModuleBuilder>()();

          return TabContainerScreen(
            content: TabContainerContent(
                firstTab: profileTab, secondTab: searchTab, thirdTab: adsTab),
          );
        });

//------------------------------------------------------------------------------
  }
}

标签: flutterdartbloc

解决方案


我的项目中有同样的错误。

就我而言,我需要重用 StreamController。场景是,有重置按钮从头开始搜索信息。

反正我是这样解决的。

  1. 添加.close()到重置按钮。
  2. 在搜索中再次初始化 StreamController。
    if (streamController.isCloded) {
    streamController = new StreamController<List<A>>(); 
    }

在您的情况下,我认为 tabview 重新生成(或重新构建?)视图。所以 StreamController 重新初始化。

我认为您会在 initState 中添加初始化 StreamContrller。

@override
void initState(){
super.initState();
if (streamController == null){
    streamController = new StreamController();
}

我希望这会对你有所帮助。


推荐阅读