监听 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();
}