Flutter BLoC - StreamSubscription 不监听调度事件
Flutter BLoC - StreamSubscription not listen on dispatched event
我正在使用 Flutter BLoC 包来管理我的应用程序的状态,但是自上次包更新 (v0.22.1) 以来,我的行为很奇怪。
简单地说,我在 EventsBloc
中的 PositionBloc
状态上有一个 StreamSubscription
侦听器,但是当我从 PositionBloc
添加事件时,侦听器不起作用。
最奇怪的是,我第一次从 EventsBloc
添加事件时监听器工作,但之后似乎完全被忽略了。
这是我的构建树:
main.dart
:这里我展示的是首页或者是基于认证的登录页面。 AuthenticationBloc
和 MoviesBloc
并不重要,或者 LocalsBloc
重点是 PositionBloc
。
class App extends StatelessWidget {
...
@override
Widget build(BuildContext context) {
return BlocProvider(
builder: (context) => MoviesBloc()..add(LoadMovies()),
child: MaterialApp(
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is Unauthenticated) {
return Login(
authenticationRepository: _authenticationRepository,
);
}
if (state is Authenticated) {
return MultiBlocProvider(
providers: [
BlocProvider<LocalsBloc>(
builder: (context) => LocalsBloc()..add(LoadLocals()),
),
BlocProvider<PositionBloc>(
builder: (context) => PositionBloc(
localsBloc: BlocProvider.of<LocalsBloc>(context),
),
)
],
child: Home(),
);
}
return Splash();
},
),
),
);
}
}
home.dart
:这是管理TabBarView
的StatefulWidget
,这里我向小部件EventsCarousel
提供EventsBloc
。在 SearchBar
小部件中,我有调度事件的触发器,因此根据所选位置重建 EventsCarousel
。
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
...
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: TabBarView(
children: <Widget>[
Stack(
alignment: Alignment.topCenter,
children: <Widget>[
BlocProvider<EventsBloc>(
builder: (context) => EventsBloc(),
child: EventsCarousel(),
),
Positioned(
child: SearchBar(),
),
],
),
MoviesList(),
Settings(),
],
controller: _tabController,
),
),
bottomNavigationBar: Material(
child: TabBar(
indicatorColor: Colors.deepOrange,
tabs: <Tab>[
Tab(
icon: Icon(
FontAwesomeIcons.home
),
),
Tab(
icon: Icon(
FontAwesomeIcons.bullhorn,
),
),
Tab(
icon: Icon(
FontAwesomeIcons.cogs,
),
),
],
controller: _tabController,
),
),
);
}
search_bar.dart
:这是一个 StatefulWidget
用于管理 _textController
和 _focusNode
。在这里,我有我的应用程序状态转换器。我使用 Flutter TypeAhead 包来构建搜索栏,我的搜索栏条目来自 LocalsBloc
,我们在 main.dart 中看到。当我点击一个条目时,我将事件 UpdatePosition
(local) 添加到 PositionBloc
.
class _SearchBarState extends State<SearchBar> {
...
@override
Widget build(BuildContext context) {
return BlocBuilder<PositionBloc, PositionState>(
builder: (context, state) {
if (state is PositionUpdated) {
if (!_focusNode.hasFocus) {
_textController.text = state.position.local.description;
}
return Container(
decoration: BoxDecoration(
color: Colors.white,
),
width: MediaQuery.of(context).size.width * 0.75,
child: TypeAheadField<Local>(
getImmediateSuggestions: true,
textFieldConfiguration: TextFieldConfiguration(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
hintText: "Inserisci una posizione",
contentPadding: EdgeInsets.all(15),
),
focusNode: _focusNode,
controller: _textController,
),
suggestionsCallback: (String pattern) {
return (BlocProvider.of<LocalsBloc>(context).state as LocalsLoaded)
.locals
.where(
(local) =>
local.description
.toLowerCase()
.contains(pattern.toLowerCase()),
)
.toList();
},
noItemsFoundBuilder: (context) {
return Text('Nessun risultato trovato');
},
itemBuilder: (context, Local suggestion) {
return Card(
child: ListTile(
title: Text(suggestion.description),
subtitle: Text(suggestion.town),
trailing: Icon(Icons.gps_not_fixed),
),
);
},
onSuggestionSelected: (Local suggestionSelected) {
BlocProvider.of<PositionBloc>(context).add(
UpdatePosition(suggestionSelected),
);
}),
);
} else {
return Container();
}
},
);
}
我有事件和状态的标准 Bloc 样板,特别是 EventsBloc,正如我所说我有这个订阅:
EventsBloc({@required PositionBloc positionBloc})
: assert(PositionBloc != null),
_positionBloc = positionBloc {
positionSubscription = positionBloc.listen((state) {
if (state is PositionUpdated) {
add(LoadEvents(state.local));
}
});
此侦听器在第一个小部件树构建后不起作用,但是当我从搜索栏中的条目选择中添加事件 UpdatePosition 时,PositionBloc 的状态发生变化并且事件正确映射到 PositionUpdated。这是一个很奇怪的情况,可以帮助我吗?
我刚刚注意到我在 CTORs 初始值设定项中为我的 PositionUpdated
状态错过了一个超级调用,因此没有调用侦听器。这是我的错误,我在调试中已经跟踪了三天。
我正在使用 Flutter BLoC 包来管理我的应用程序的状态,但是自上次包更新 (v0.22.1) 以来,我的行为很奇怪。
简单地说,我在 EventsBloc
中的 PositionBloc
状态上有一个 StreamSubscription
侦听器,但是当我从 PositionBloc
添加事件时,侦听器不起作用。
最奇怪的是,我第一次从 EventsBloc
添加事件时监听器工作,但之后似乎完全被忽略了。
这是我的构建树:
main.dart
:这里我展示的是首页或者是基于认证的登录页面。 AuthenticationBloc
和 MoviesBloc
并不重要,或者 LocalsBloc
重点是 PositionBloc
。
class App extends StatelessWidget {
...
@override
Widget build(BuildContext context) {
return BlocProvider(
builder: (context) => MoviesBloc()..add(LoadMovies()),
child: MaterialApp(
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is Unauthenticated) {
return Login(
authenticationRepository: _authenticationRepository,
);
}
if (state is Authenticated) {
return MultiBlocProvider(
providers: [
BlocProvider<LocalsBloc>(
builder: (context) => LocalsBloc()..add(LoadLocals()),
),
BlocProvider<PositionBloc>(
builder: (context) => PositionBloc(
localsBloc: BlocProvider.of<LocalsBloc>(context),
),
)
],
child: Home(),
);
}
return Splash();
},
),
),
);
}
}
home.dart
:这是管理TabBarView
的StatefulWidget
,这里我向小部件EventsCarousel
提供EventsBloc
。在 SearchBar
小部件中,我有调度事件的触发器,因此根据所选位置重建 EventsCarousel
。
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
...
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: TabBarView(
children: <Widget>[
Stack(
alignment: Alignment.topCenter,
children: <Widget>[
BlocProvider<EventsBloc>(
builder: (context) => EventsBloc(),
child: EventsCarousel(),
),
Positioned(
child: SearchBar(),
),
],
),
MoviesList(),
Settings(),
],
controller: _tabController,
),
),
bottomNavigationBar: Material(
child: TabBar(
indicatorColor: Colors.deepOrange,
tabs: <Tab>[
Tab(
icon: Icon(
FontAwesomeIcons.home
),
),
Tab(
icon: Icon(
FontAwesomeIcons.bullhorn,
),
),
Tab(
icon: Icon(
FontAwesomeIcons.cogs,
),
),
],
controller: _tabController,
),
),
);
}
search_bar.dart
:这是一个 StatefulWidget
用于管理 _textController
和 _focusNode
。在这里,我有我的应用程序状态转换器。我使用 Flutter TypeAhead 包来构建搜索栏,我的搜索栏条目来自 LocalsBloc
,我们在 main.dart 中看到。当我点击一个条目时,我将事件 UpdatePosition
(local) 添加到 PositionBloc
.
class _SearchBarState extends State<SearchBar> {
...
@override
Widget build(BuildContext context) {
return BlocBuilder<PositionBloc, PositionState>(
builder: (context, state) {
if (state is PositionUpdated) {
if (!_focusNode.hasFocus) {
_textController.text = state.position.local.description;
}
return Container(
decoration: BoxDecoration(
color: Colors.white,
),
width: MediaQuery.of(context).size.width * 0.75,
child: TypeAheadField<Local>(
getImmediateSuggestions: true,
textFieldConfiguration: TextFieldConfiguration(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
hintText: "Inserisci una posizione",
contentPadding: EdgeInsets.all(15),
),
focusNode: _focusNode,
controller: _textController,
),
suggestionsCallback: (String pattern) {
return (BlocProvider.of<LocalsBloc>(context).state as LocalsLoaded)
.locals
.where(
(local) =>
local.description
.toLowerCase()
.contains(pattern.toLowerCase()),
)
.toList();
},
noItemsFoundBuilder: (context) {
return Text('Nessun risultato trovato');
},
itemBuilder: (context, Local suggestion) {
return Card(
child: ListTile(
title: Text(suggestion.description),
subtitle: Text(suggestion.town),
trailing: Icon(Icons.gps_not_fixed),
),
);
},
onSuggestionSelected: (Local suggestionSelected) {
BlocProvider.of<PositionBloc>(context).add(
UpdatePosition(suggestionSelected),
);
}),
);
} else {
return Container();
}
},
);
}
我有事件和状态的标准 Bloc 样板,特别是 EventsBloc,正如我所说我有这个订阅:
EventsBloc({@required PositionBloc positionBloc})
: assert(PositionBloc != null),
_positionBloc = positionBloc {
positionSubscription = positionBloc.listen((state) {
if (state is PositionUpdated) {
add(LoadEvents(state.local));
}
});
此侦听器在第一个小部件树构建后不起作用,但是当我从搜索栏中的条目选择中添加事件 UpdatePosition 时,PositionBloc 的状态发生变化并且事件正确映射到 PositionUpdated。这是一个很奇怪的情况,可以帮助我吗?
我刚刚注意到我在 CTORs 初始值设定项中为我的 PositionUpdated
状态错过了一个超级调用,因此没有调用侦听器。这是我的错误,我在调试中已经跟踪了三天。