Bloc 要么多次调用,要么根本没有被调用

Bloc is either calling multiple times or not getting called at all

我有 2 个屏幕

  1. Screen A
  2. Screen B

我通过以下代码从 screen A 转到 Screen B

    onTap: () {
      Navigator.pushNamed(context, '/screen_b');
    },

屏幕B码

class ScreenB extends StatefulWidget {
  @override
  _ScreenBState createState() => _ScreenBState();
}

class _ScreenBState extends State<ScreenB> {

   SampleBloc sampleBloc;

    @override
    void initState() {
       super.initState();
       sampleBloc = BlocProvider.of<SampleBloc>(context);

       sampleBloc.stream.listen((state) {
          // this is getting called multiple times.
       }
    }

    @override
    void dispose() {
       super.dispose();
       sampleBloc.clear(); // If i add this, no event is firing from second time i come to the page. initState() is being called i checked so sampleBloc is not null.
    }
   
    
    @override
    Widget build(BuildContext context) {
       ....
           onTap: () {
              sampleBloc.add(CreateSampleEvent());
           },
       ....
    }

}

当我点击点击将 CreateSampleEvent 添加到屏幕 B 中的 sampleBloc 时,'sampleBloc.stream.listen' 被触发多次。

Sample outcome

Step 1. First do sampleBloc.add (tap) -> sampleBloc.stream.listen fired one time
Step 2. Go back to Screen A and come back to Screen B Second go sampleBloc.add (tap) -> In one case i saw the firing takes place in a pair of 2 times, and in other times the firing takes place in pair of 4 times.

class SampleBloc extends Bloc<SampleEvent, SampleState> {
  final SampleRepository sampleRepository;

  SampleBloc({this.sampleRespository}) : super(null);


  @override
  Stream<SampleState> mapEventToState(SampleEvent event) async* {
    if (event is SampleEvent) {
      yield* mapSampleEventToState();
    }
  }

  Stream<SampleEvent> mapSampleEventToState() async* {
    yield SampleInProgressState();
    try {
      String sampleId = await sampleRepository.createSample();
      if (sampleId != null) {
        yield SampleCompletedState(sampleId, uid);
      } else {
        yield SampleFailedState();
      }
    } catch (e) {
      print('Error: $e');
      yield SampleFailedState();
    }
  }

知道可能出了什么问题吗?

由于您正在创建手动订阅(通过获取 Bloc 然后收听 stream),因此您还需要手动取消 该订阅,当您完成它,否则,SampleBloc 将继续获取新订阅并为所有订阅生成事件。

为此,您可以:

  1. 保存订阅,然后在dispose()方法中取消。
   SampleBloc sampleBloc;
   StreamSubscription _subscription;

    @override
    void initState() {
       super.initState();
       sampleBloc = BlocProvider.of<SampleBloc>(context);

       _subscription = sampleBloc.stream.listen((state) {
          // this is getting called multiple times.
       }
    }
    
   @override
   void dispose() {
     _subscription.cancel();
     super.dispose();
   }
  1. 您可以利用包中的 BlocListener,这是一个自动处理的小部件,因此删除它创建的订阅。
BlocListener<BlocA, BlocAState>(
  listener: (context, state) {
    // do stuff here based on BlocA's state
  },
  child: Container(),
)