Bloc: Bad state: Cannot add new events after calling close

Created on 27 Jul 2019  ·  2Comments  ·  Source: felangel/bloc

Describe the bug
I'm working on an app that has three tabs. The blocs is created on the HomeScreen (see https://github.com/fsjovatsen/atp_app/blob/master/lib/screens/home/HomeScreen.dart). I use MultiBlocProvider to pass the blocs down. Two of the screens needs the same bloc (DogBloc and TrainingSessionBloc). The issues is when I navigate between those to screens there is no problem with the DogBloc but only with the TrainingSessionBloc.

I'm pretty new to flutter and bloc (my first app) so bear with me :)

To Reproduce
Steps to reproduce the behavior:

  1. Go to Dog screen and press the play button. This will take you to a new training session screen. After pressing play on this screen you will be taken to a new screen where you log your session. When pressing the stop button the TrainingSessionBloc is used to save the session.
  2. The go to the Log screen. If you select a dog we get a Bad state: Cannot add new events after calling close.
  3. If you restart the application and do it the other way around and go to the Log screen first this will work, but then saving a new training session gives the error.

*Logs *

Analyzing atp_app...                                                    

   info • The value of the field '_database' isn't used • lib/data/AppDatabase.dart:17:12 • unused_field
   info • This method overrides a method annotated as @mustCallSuper in 'AutomaticKeepAliveClientMixin', but does not invoke the overridden method • lib/screens/dog/dog_screen.dart:38:10 • must_call_super
   info • This method overrides a method annotated as @mustCallSuper in 'AutomaticKeepAliveClientMixin', but does not invoke the overridden method • lib/screens/home/HomeScreen.dart:64:10 • must_call_super
   info • This method overrides a method annotated as @mustCallSuper in 'AutomaticKeepAliveClientMixin', but does not invoke the overridden method • lib/screens/logs/logs_screen.dart:29:10 • must_call_super
   info • This method overrides a method annotated as @mustCallSuper in 'AutomaticKeepAliveClientMixin', but does not invoke the overridden method • lib/screens/protocol/ProtocolScreen.dart:24:10 • must_call_super
   info • Unused import: 'package:location/location.dart' • lib/screens/training_session/new_session/location_card.dart:4:8 • unused_import
   info • This method overrides a method annotated as @mustCallSuper in 'AutomaticKeepAliveClientMixin', but does not invoke the overridden method • lib/screens/training_session/new_session/new_training_session_screen.dart:56:10 •
          must_call_super
   info • 'fromAsset' is deprecated and shouldn't be used • lib/screens/training_session/new_session/new_training_session_screen.dart:240:30 • deprecated_member_use
   info • Unused import: 'package:atp_app/bloc/bloc.dart' • lib/screens/training_session/new_session/protocol_card.dart:1:8 • unused_import
   info • Unused import: 'package:flutter_bloc/flutter_bloc.dart' • lib/screens/training_session/new_session/protocol_card.dart:4:8 • unused_import
   info • This method overrides a method annotated as @mustCallSuper in 'AutomaticKeepAliveClientMixin', but does not invoke the overridden method • lib/screens/training_session/session/session_screen.dart:33:10 • must_call_super
[✓] Flutter (Channel stable, v1.7.8+hotfix.4, on Mac OS X 10.14.5 18F203, locale en-GB)
    • Flutter version 1.7.8+hotfix.4 at /Users/fsjovatsen/bin/flutter
    • Framework revision 20e59316b8 (8 days ago), 2019-07-18 20:04:33 -0700
    • Engine revision fee001c93f
    • Dart version 2.4.0


[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/fsjovatsen/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • Java binary at: /Users/fsjovatsen/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/183.5692245/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 10.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 10.3, Build version 10G8
    • CocoaPods version 1.7.2

[✓] iOS tools - develop for iOS devices
    • ios-deploy 1.9.4

[✓] Android Studio (version 3.4)
    • Android Studio at /Users/fsjovatsen/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/183.5692245/Android Studio.app/Contents
    • Flutter plugin version 37.0.1
    • Dart plugin version 183.6270
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1343-b01)

[✓] IntelliJ IDEA Ultimate Edition (version 2019.1.3)
    • IntelliJ at /Users/fsjovatsen/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
    • Flutter plugin version 36.1.4
    • Dart plugin version 191.7830

[✓] VS Code (version 1.36.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.2.0

[✓] Connected device (1 available)
    • iPhone Xʀ • F2B98425-B96E-4341-B8ED-865BFC8AA5A5 • ios • com.apple.CoreSimulator.SimRuntime.iOS-12-4 (simulator)

• No issues found!
question

Most helpful comment

Thanks, that helped @felangel 👍

All 2 comments

Hi @fsjovatsen 👋
Thanks for opening an issue!

I opened a pull request to fix the various issues around flutter_bloc.

The main problem is you need to keep in mind that BlocProvider will make it's bloc available to all widgets in the sub-tree (new routes are not considered part of the sub-tree). As a result, you should generally create a single BlocProvider per bloc at the common ancestor of all widgets that need the bloc using BlocProvider(builder: (context) => MyBloc(), child: MyChild()). When you use BlocProvider with a builder you should always make sure you're actually building a new bloc instance and keep in mind that BlocProvider will automatically dispose the bloc for you (no need for StatefulWidgets.

When you are providing a bloc to a new MaterialPageRoute, you should wrap the route in BlocProvider.value to provide the bloc to the new route without automatically disposing the bloc.

You can check out the flutter_bloc core concepts section in the documentation for more details.

In addition, you can check out the bloc access recipe for more details around how/why to use BlocProvider to make blocs available to different parts of your application.

Hope that helps! 👍

Thanks, that helped @felangel 👍

Was this page helpful?
0 / 5 - 0 ratings