ChangeNotifierProvider: can its created ChangeNotifier get recreated? - flutter

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.

Related

BlocBuilder vs BlocListener

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

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.

Is it safe to keep a reference of a state in Flutter?

I get the general idea that the StatefulWidget my get rebuild very often, and even get assigned to a different State if not using key in some cases. However the State of that widget always exists in memory. I need to change some data of the State when it's not shown. Is it safe to keep the reference of that State instance for example in a singleton and change its data?
Specifically, I have a StatefulWidget(call it homapage) with PageView. Its State keeps the reference of the PageController. I want to change the controller.page when the screen is showing other tabs rather than homepage. I did this via keeping a reference of the State in a singleton. In order to do it, I need to make the State class public by deleting the _ in front of the State class name. If feels unsafe and against the Flutter design philosophy to me.
The state will be destroyed when a widget that uses that state is no longer in the widget tree. We recommend that you use GlobalKey and don't use a singleton as a reference to the State. Using InheritedWidget is also a good option.

A better architecture than passing callback functions to children Widgets

I'm building my first Flutter app, in which I need to refresh a list of data, and every component has some modifiers.
This is the basic architecture.
A big list of data (about 5000 rows) is periodically refreshed from an API inside a RefresherWidget (which is a StatefulWidget that holds the list), and then passed along to the children.
Every RowWidget has a Switch (and Dialogs too) that modifies the data it represents.
Currently, the methods to modify the list are in the RefresherWidget, so I'm passing them as callback functions inside every children until reaching the onChanged callback of the Switch.
But I don't think it's a very clean solution, and I don't know how to implement a better one: I've tried thinking about passing these methods inside an InheritedWidget that stays between RefresherWidget and ListViewWidget, and referencing them using the of function, but I don't know about the perfomance hit I would get if the InheritedWidget gets rebuild.
Also, Streams and BLoCs seem very complicated for what I need to do.
How do you guys usually approach a problem like this?
This is definitely a situation for InheritedWidget or BuildContext in general.
I've tried [...] InheritedWidget [...] but I don't know about the perfomance hit I would get if the InheritedWidget gets rebuild.
You don't have to fear anything. InheritedWidget is built for this exact purpose.
Obtaining the InheritedWidget is very performant (O(1)). And only widgets that depends on the value gets rebuilt – which is optimal too.