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.
Related
I need to reset state of child BLOC when state of parent BLOC is changed. Let's say I have an image which is managed by ChildBloc which have a method for image scaling (so ChildBloc.state has a scale property).
When user scales image the current scale is saved in ChildBloc state and persistent. When user goes out from the page and returned back the scale must be restored.
When user changes image (let's say select new item in images list and of couuse state of ParentBloc is changed then state of ChildBloc must be set to initial and any persistence must be cleared.
Any idea how do I need to link states of those BLOCs? Is it a good idea to keep state of ChildBloc as part of state of ParentBloc?
It's hard to tell what the best state management approach is without knowing what the application does and how it works.
Anyway, in your case you have at least 2 options:
Unify the Parent and Child states. This approach would solve your problem as you have all the state in a single bloc. But it could be a really big change (again, depends on how your ChildBloc is structured)
Refer to ChildBloc inside a ParentBloc event. I guess that when the user changes image in the ParentBloc you throw an event. You could refer to che ChildBloc and throw a resetState event.
Something like: context.read<ChildBloc>().resetState(ResetStateEvent(...));. You need the BuildContext to do this, but you can pass it in the ParentBloc event.
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.
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.
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.
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.