I'm sorry if my terminology is misplaced or if this has been answered before but I'm a little lost on the concept of passing, accessing blocs, navigating through widgets, and still having access to those blocs. Thank you in advance!
From the last issue I opened, you pointed me in the right direction of declaring blocs when you need them instead of creating all the instances in the main.dart and providing them through MutliBlocProviders. Which makes sense since it doesn't have to climb the widget tree to access that instance and is great for many other use cases.
However, I am encountering many cases where I get a warning indicating Bad state: Cannot add new events after calling close. So after looking at other issues, I learned I needed to create the bloc one level higher than the current page that I needed it on. When I did that, it works, in some cases...
I am passing the bloc to a screen with a BlocProvider, but I am still getting the same issue in some cases. Along with that, in some cases when I access the bloc with BlocProvider.of(context). It's not declared within that context when trying to access it beyond the widget I provided it to. So that leaves me wondering, when does it branch off into a different 'context' or subtree which makes it lose the reference to that bloc? Keep in mind, when navigating to different screens, I am using
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
I can avoid the issue when I pass the bloc through the constructor instead of BlocProvider, in some cases... So now instead of bad state: cannot add events after calling close, it just works. But that doesn't mean it will always work when navigating through screens in the situations I faced. Plus it gets messy when I need to access that same bloc 3 widgets down the widget tree all while repeatedly passing the bloc through each constructor. However, in some cases when I get deep within the widget tree, I still run into problems with the event closing. Even when I don't dispose of the bloc. From my understanding, this should happen when a bloc gets disposed. But the strange part is, I put breakpoints and print statements and nothing is calling the dispose method. Even when I removed the bloc from disposing, I still get the issue.
One specific issue i am having right now is lets say for example, I have a bloc called 'SampleBloc' that I created on Screen A and I need it on Screen B, SearchDelegate, and Screen D.
Screen A (bloc declared, and disposed) -> Screen B(bloc passed through constructor)
-> Screen C(bloc passed through constructor)
-> SearchDelegate(passed through constructor) -> ScreenD (passed through contructor)
Lets say I navigate all the way to screen D, everything works. If I press the back button back to the SearchDelegate and perform another search, I get the bad state: Cannot add new events after calling close.
or
Screen A (bloc declared, disposed, and bloc passed with BlocProvider)
-> Screen B (accessed through BlocProvider) can access
-> Screen C (accessed through BlocProvider) can't access (event closed)
-> SearchDelegate (accessed through BlocProvider) can't access (can't find bloc)
-> ScreenD (accessed through BlocProvider) can't access (can't find bloc)
So my last solution was using an inheritedWidget. Which this case always fails because I lose reference the moment I try to access it within my search delegate and I need it there and on Screen D. I feel like I am missing or not understanding a few core concepts. If you could point me in the right direction and any good practices when passing and accessing blocs, I would appreciate it very much.
Again, thank you for your time and for making this library!!
Hi @carmenkerim12 馃憢
Thanks for opening an issue!
The rule of thumb is only provide a bloc where it is needed. With flutter_bloc v0.20.0 you can provide and access a bloc using BlocProvider within the same BuildContext which should reduce the number of widgets needed.
When you push a route or use a SearchDelegate etc... you are creating a new widget with a totally different BuildContext (think of it as being disconnected from the rest of the widget tree) and so you lose access to blocs that you provided.
There are two main strategies to avoid having to pass blocs via constructor:
MaterialApp.BlocProvider (make sure to use BlocProvider.value to avoid double disposing the bloc)With option 1 you are essentially making the bloc accessible throughout the entire widget tree whereas option 2 allows you to scope the bloc to only the routes that need it.
You can check out the bloc access recipe for examples of different ways to access a bloc throughout the widget tree.
In cases like the SearchDelegate you will likely need to just pass the bloc via constructor since you can't wrap the SearchDelegate in a BlocProvider due to the type restriction.
Hope that helps! 馃憤
Regarding the bad state error can you share a link to a sample app which illustrates the issue? I would be more than happy to take a look and help debug the issue 馃槃
@felangel I got the same issue on the new release v0.20
I disabled automatic disposable which introduced in this issue
https://github.com/felangel/bloc/issues/380
https://github.com/felangel/bloc/pull/385
I used .value
But I think disposable flag could be more clear in this case instead of .value

@felangel Thank you for taking the time to help me out. Everything you said makes a lot of sense and cleared that concept up for me. I'm going to try out the second strategy for accessing the bloc and to try out passing the bloc via constructor to the searchDelegate. I'm going to then test if I still encounter the bad state error. If I do, I'll get back to you with a sample project replicating the error as soon as possible! Thank you again man!
No problem and sounds good!
Closing for now but feel free to comment if you encounter the error and I'm happy to help resolve it 馃憤
Most helpful comment
@felangel Thank you for taking the time to help me out. Everything you said makes a lot of sense and cleared that concept up for me. I'm going to try out the second strategy for accessing the bloc and to try out passing the bloc via constructor to the searchDelegate. I'm going to then test if I still encounter the bad state error. If I do, I'll get back to you with a sample project replicating the error as soon as possible! Thank you again man!