监听 bloc 被多次调用
Listening of bloc getting called multiple times
我的屏幕上有这个用于收听 bloc 的代码。
late MyBloc myBloc;
@override
void initState() {
print('inside init state');
super.initState();
myBloc = BlocProvider.of<MyBloc>(context);
myBloc.stream.listen((state) {
if (state is MyAddCompletedState) {
print('listening to bloc');
}
}
}
如果我添加一个事件,它会打印一次listening to bloc。如果我转到另一个屏幕并 return 到同一屏幕,它将打印 listening to bloc 两次。好像我做的第一个 listen 还是活跃的。接下来,我尝试 close 我认为它会停止第一个 listen =40=]。这样当我回到屏幕时,它会有一个新鲜的 listen 但它会出现错误:错误状态:调用关闭后无法添加新事件。我试图对此进行研究,并且有人提到要处置该集团,但它不再具有该语法。请帮助我更改屏幕后如何正确关闭或阻止它收听。谢谢!
//this is found on my screen
late MyBloc myBloc;
@override
void initState() {
print('inside init state');
super.initState();
myBloc = BlocProvider.of<MyBloc>(context);
myBloc.stream.listen((state) {
if (state is MyAddCompletedState) {
print('listening to bloc');
}
}
}
@override
void dispose() {
myBloc.close();
// myBloc.dispose(); --> I saw some tutorial to use this but it doesn't work
super.dispose();
}
这是我的 main.dart:
return FutureBuilder(
future: InitFirst.instance.initialize(),
builder: (context, AsyncSnapshot snapshot) {
return MultiBlocProvider(
providers: [
BlocProvider<MyBloc>(
create: (context) => MyBloc(
authenticationRepository: authenticationRepository,
userDataRepository: userDataRepository,
),
),
...
这是我触发事件的部分。在此事件 运行 之后,将触发 stream.listen。但是每次访问我的屏幕都会触发多次。
myBloc.add(MyAddEvent(
selectedName,
selectedCount);
附加说明:此事件正在触发 Firebase 中的更新,我需要检查它是否已完成,这就是我执行 stream.listen[=40= 的原因].
有多种方法可以根据上下文解决此问题。我尽量避免将 BLoC 实例化与 StatefulWidgets 一起使用。而且,我喜欢将 Cubits 与 Observers 结合使用,具体取决于进入我的流的事件。我在下面的代码中添加了其中的大部分,这些代码并没有全部使用,但供您参考。我的代码示例消除了您描述的问题。如果您能提供最低限度的可行代码,我很乐意进一步提供帮助。
以下代码是我为演示可能的策略而组合在一起的示例。 BLoC 包网站极大地启发了代码。它具有我们都熟悉的标准计数器应用程序和导航功能。
请查看以下代码是否有帮助:
请务必添加
flutter_bloc: ^8.0.1
到您的 pubspec.yaml 文件。
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
BlocOverrides.runZoned(
() => runApp(const MaterialApp(home: CounterPage())),
blocObserver: CounterObserver(),
);
}
class CounterObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print('onTransition -- bloc: ${bloc.runtimeType}, transition: $transition');
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
print('onError -- bloc: ${bloc.runtimeType}, error: $error');
super.onError(bloc, error, stackTrace);
}
@override
void onClose(BlocBase bloc) {
super.onClose(bloc);
print('onClose -- bloc: ${bloc.runtimeType}');
}
}
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
class ScoreCubit extends Cubit<int> {
ScoreCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CounterCubit>(create: (context) => CounterCubit()),
BlocProvider<ScoreCubit>(create: (context) => ScoreCubit()),
],
child: const CounterView(),
);
}
}
class CounterView extends StatelessWidget {
const CounterView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Column(
children: [
Center(
child: BlocBuilder<ScoreCubit, int>(
builder: (context, score) => Text('Score: $score'),
),
),
Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, state) {
return Text('$state',
style: Theme.of(context).textTheme.headline2);
},
),
),
],
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
heroTag: 'FAB1',
child: const Icon(Icons.add),
onPressed: () {
// format from
context.read<CounterCubit>().increment();
context.read<ScoreCubit>().increment();
}),
const SizedBox(height: 8),
FloatingActionButton(
heroTag: 'FAB2',
child: const Icon(Icons.remove),
onPressed: () {
context.read<CounterCubit>().decrement();
},
),
const SizedBox(height: 8),
FloatingActionButton(
heroTag: 'FAB3',
child: const Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text('Next Page')),
body: const Center(
child: Text('This is the next page'),
),
),
),
);
},
),
],
),
);
}
}
与 Flutter 中的所有内容一样,这当然只是众多策略中的一种。
如果 Bloc 中使用的 Stream 在不使用时不断被调用,您可能需要考虑在 dispose()
覆盖上使用 cancel()
终止 Stream。试试这个
late MyBloc myBloc;
late StreamSubscription mSub;
@override
void initState() {
print('inside init state');
super.initState();
myBloc = BlocProvider.of<MyBloc>(context);
mSub = myBloc.stream.listen((state) {
if (state is MyAddCompletedState) {
print('listening to bloc');
}
}
}
@override
void dispose() {
mSub.cancel();
super.dispose();
}
我的屏幕上有这个用于收听 bloc 的代码。
late MyBloc myBloc;
@override
void initState() {
print('inside init state');
super.initState();
myBloc = BlocProvider.of<MyBloc>(context);
myBloc.stream.listen((state) {
if (state is MyAddCompletedState) {
print('listening to bloc');
}
}
}
如果我添加一个事件,它会打印一次listening to bloc。如果我转到另一个屏幕并 return 到同一屏幕,它将打印 listening to bloc 两次。好像我做的第一个 listen 还是活跃的。接下来,我尝试 close 我认为它会停止第一个 listen =40=]。这样当我回到屏幕时,它会有一个新鲜的 listen 但它会出现错误:错误状态:调用关闭后无法添加新事件。我试图对此进行研究,并且有人提到要处置该集团,但它不再具有该语法。请帮助我更改屏幕后如何正确关闭或阻止它收听。谢谢!
//this is found on my screen
late MyBloc myBloc;
@override
void initState() {
print('inside init state');
super.initState();
myBloc = BlocProvider.of<MyBloc>(context);
myBloc.stream.listen((state) {
if (state is MyAddCompletedState) {
print('listening to bloc');
}
}
}
@override
void dispose() {
myBloc.close();
// myBloc.dispose(); --> I saw some tutorial to use this but it doesn't work
super.dispose();
}
这是我的 main.dart:
return FutureBuilder(
future: InitFirst.instance.initialize(),
builder: (context, AsyncSnapshot snapshot) {
return MultiBlocProvider(
providers: [
BlocProvider<MyBloc>(
create: (context) => MyBloc(
authenticationRepository: authenticationRepository,
userDataRepository: userDataRepository,
),
),
...
这是我触发事件的部分。在此事件 运行 之后,将触发 stream.listen。但是每次访问我的屏幕都会触发多次。
myBloc.add(MyAddEvent(
selectedName,
selectedCount);
附加说明:此事件正在触发 Firebase 中的更新,我需要检查它是否已完成,这就是我执行 stream.listen[=40= 的原因].
有多种方法可以根据上下文解决此问题。我尽量避免将 BLoC 实例化与 StatefulWidgets 一起使用。而且,我喜欢将 Cubits 与 Observers 结合使用,具体取决于进入我的流的事件。我在下面的代码中添加了其中的大部分,这些代码并没有全部使用,但供您参考。我的代码示例消除了您描述的问题。如果您能提供最低限度的可行代码,我很乐意进一步提供帮助。
以下代码是我为演示可能的策略而组合在一起的示例。 BLoC 包网站极大地启发了代码。它具有我们都熟悉的标准计数器应用程序和导航功能。
请查看以下代码是否有帮助:
请务必添加
flutter_bloc: ^8.0.1
到您的 pubspec.yaml 文件。
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
BlocOverrides.runZoned(
() => runApp(const MaterialApp(home: CounterPage())),
blocObserver: CounterObserver(),
);
}
class CounterObserver extends BlocObserver {
@override
void onChange(BlocBase bloc, Change change) {
super.onChange(bloc, change);
print('${bloc.runtimeType} $change');
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print('onTransition -- bloc: ${bloc.runtimeType}, transition: $transition');
}
@override
void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
print('onError -- bloc: ${bloc.runtimeType}, error: $error');
super.onError(bloc, error, stackTrace);
}
@override
void onClose(BlocBase bloc) {
super.onClose(bloc);
print('onClose -- bloc: ${bloc.runtimeType}');
}
}
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
class ScoreCubit extends Cubit<int> {
ScoreCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
class CounterPage extends StatelessWidget {
const CounterPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<CounterCubit>(create: (context) => CounterCubit()),
BlocProvider<ScoreCubit>(create: (context) => ScoreCubit()),
],
child: const CounterView(),
);
}
}
class CounterView extends StatelessWidget {
const CounterView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Column(
children: [
Center(
child: BlocBuilder<ScoreCubit, int>(
builder: (context, score) => Text('Score: $score'),
),
),
Center(
child: BlocBuilder<CounterCubit, int>(
builder: (context, state) {
return Text('$state',
style: Theme.of(context).textTheme.headline2);
},
),
),
],
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
heroTag: 'FAB1',
child: const Icon(Icons.add),
onPressed: () {
// format from
context.read<CounterCubit>().increment();
context.read<ScoreCubit>().increment();
}),
const SizedBox(height: 8),
FloatingActionButton(
heroTag: 'FAB2',
child: const Icon(Icons.remove),
onPressed: () {
context.read<CounterCubit>().decrement();
},
),
const SizedBox(height: 8),
FloatingActionButton(
heroTag: 'FAB3',
child: const Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(title: const Text('Next Page')),
body: const Center(
child: Text('This is the next page'),
),
),
),
);
},
),
],
),
);
}
}
与 Flutter 中的所有内容一样,这当然只是众多策略中的一种。
如果 Bloc 中使用的 Stream 在不使用时不断被调用,您可能需要考虑在 dispose()
覆盖上使用 cancel()
终止 Stream。试试这个
late MyBloc myBloc;
late StreamSubscription mSub;
@override
void initState() {
print('inside init state');
super.initState();
myBloc = BlocProvider.of<MyBloc>(context);
mSub = myBloc.stream.listen((state) {
if (state is MyAddCompletedState) {
print('listening to bloc');
}
}
}
@override
void dispose() {
mSub.cancel();
super.dispose();
}