BlocBuilder vs BlocListener - flutter

I have a very specific question when reading the documentation.
After reading the BlocBuilder documentation, I then went on by reading about the BlocListener. Everything was pretty clear, until I read this:
The listener is guaranteed to only be called once for each state
change unlike the builder in BlocBuilder.
As I understand, in BlocBuilder the builder: gets called every time the bloc state changes (of course in the case in which buildWhen: is omitted and it always returns true as a default value). And in BlocListener the listener: gets called in response to state changes in the bloc.
I can't seem to understand the concept behind the quoted text. Doesn't the builder: in BlocBuilder also get called once for every change in the state of the bloc? Where's that "second" call I'm missing happening?

The builder is run as you say upon state change. But the builder function is also run when the framework deems necessary to rebuild.
The listener function is not affected by the frameworks need to rebuild.

Every time when a new state is emitted by the bloc it is compared with the previous one, and if they are DIFFERENT, the listener function is triggered.
If in you situation, you are using Equatable with only LoadedState as props, which means when two states are compared only the LoadedState are tested. In this way BLoC consumer thinks that the two states are equal and do not triggers the listener function again.
if you want to update same state just add one state before calling your updating state like this, if you want to update 'LoadedState' state again call 'LoadingState' state before that and than call 'LoadedState' state so BlocListener and BlocBuilder will listen to it

Related

Flutter BlocListener how to call events from another bloc?

I can't figure out whats allowed to use and what shouldn't be done. From web im reading:
BLOCLISTENER BlocListener is a Flutter widget that takes a
BlocWidgetListener and an optional bloc and calls the listener when
the state of the bloc changes. It should be used for functionality
that only happens once per state change, such as navigation,
displaying a SnackBar, displaying a dialog, and so on.
BlocListener will automatically conduct a lookup using BlocProvider
and the current BuildContext if the bloc parameter is omitted.
Now I have a quite complex app structure and I need to call 2 Events from another bloc. This is my code:
return BlocListener<LiveeventsBloc, LiveeventsState>(
listener: (context, state) {
// TODO: implement listener
if (state is LiveeventFinishedState) {
print('LiveeventFinishedState');
BlocProvider.of<EventsBloc>(context).add(LoadJoinableEvent()); // Event from another bloc
BlocProvider.of<EventsBloc>(context).add(LoadEventsEvent()); // Event from another bloc
}
},
Now Im not sure, can I call events from another bloc now? It's not clear to me what is allowed to do. The first event is fetching data and providing a button in UI depending on the result, the second event is fetching data and displaying it.

Does setState() inherently affect the application performance?

I read that setState affect application performance because it rebuilds the widget tree.
Calling setState notifies the framework that the internal state of
this object has changed in a way that might impact the user interface
in this subtree, which causes the framework to schedule a build for
this State object.
Is this an actual concern for application performance?
Yeah, it may but only if you are calling the function too many times unnecessarily.
What's the best practice?
Try calling it at the end of functionality or only when you need to
update the widget, you can also create multiple subclasses ( stateful
widget), so if you want some changes in a particular area only, then
only that widget will get updated not the entire screen.

Where to initialize bloc?

In one of my projects, I am using flutter_bloc package.
In that example, I instantiated bloc inside didChangeDependencies(). So bloc lives during the lifecycle of a screen.
However, my colleague told me not to initialize there. He said bloc should be initialized in app.dart where It can live over the lifecycle of the app. Because, in cases where there should be multiple screens on tablet, it will break the code.
For example, I have ScreenA, ScreenB and ScreenC. you can go to ScreenB and ScreenC through ScreenA. ScreenB and ScreenC use the same bloc, and bloc is initialized sepearately in each screens. He is saying that if the requirement is to show ScreenB and ScreenC simultaneously on a tablet, it might break the code. How?
Could you suggest me what is best? Or does it depend on the usecase?
It is the best practice to initiate bloc instance during initState as it runs only once per widget lifecycle. didChangeDependencies() may be called multiple times for example if widget is moved in the widget tree or widget gets notified of InheritedWidget change, so bloc will get new instance like that and you dont want that. What your collegue is talking is more about BlocProviders scope and sure is normal practice, but for some small-usecase-bloc might be redundant. That is up to you to decide does your whole app needs to be in scope of this bloc. Keep in mind that if lazy property is not set to false, your bloc will be created with the first call to it.

How does BlocProvider.value works with added Event

What will happen if An event is added to the bloc being passed inside the BlocProvider.value?
Will the event gets added before or after i get to the page?
And Is Blocprovider.value an ideal way to avoid adding events to bloc in initState() method?
I'm trying to avoid initstate as I'm listening to Stream of data from firebase (this event need to be called only once).
I found a workaround for this,
Using the approach stated above will make the LoadProductFromStream event get called even before getting to /opening the StreamproductPage().
To avoid this a simple and efficient approach could be used instead
create a wrapper widget
create the body (the main widget to display results)
Below is an image attached to explain this
Wrapper widget is where the bloc will be created/initialized
and where LoadProductFromStream() event will be added to the bloc
In conclusion
This way we only add LoadFromStream() event to bloc when we get to StreamproductPage
Takeaway
BlocProvider(create:(context)=> xyzBloc()) // can automatically close bloc
while
BlocProvider.value() // doesn't close bloc automatically
(i stand to be corrected)

ChangeNotifierProvider: can its created ChangeNotifier get recreated?

Can a ChangeNotifierProvider's ChangeNotifier get recreated?
My impression from reading this is that when a ChangeNotifierProvider does create: (context) => SomeChangeNotifier(), SomeChangeNotifier is guaranteed to never be recreated:
This is done one time when the widget is first built, and not on subsequent rebuilds.
This is what I would hope and expect. However, according to the Flutter documentation:
ChangeNotifierProvider is smart enough not to rebuild [its ChangeNotifier] unless absolutely necessary.
Note the "unless absolutely necessary" part, which suggests that the ChangeNotifier can be recreated.
What you need to understand is that the lifecycle of a ChangeNotifier depends on the lifecycle of what you are providing.
for example, if you want the state of a view to be alive all the while the app is not closed, then you would make it global and declare it above the MaterialApp.
But sometimes you might want the recreate the state of a particular view for example,
if the views are so, 1->2->3 then 3rd view might want to be reset, and this time you provide it only above the route which resets the state and rebuilds when accessed again.
I believe this is what
ChangeNotifierProvider is smart enough not to rebuild [its ChangeNotifier] unless absolutely necessary.
means
You could also manually call dispose on it whenever you want even if its provided globally.