Inherit The State
The InheritedWidget is fundamental to supplying efficient performance.
Although Flutter has made great strides in being as efficient as possible,
it's declarative approach will, in most cases, rebuild the whole screen
whereas an InheritedWidget allows you to rebuild only what's changed on the screen.
When it comes down to it, the less that's rebuilt, the better the performance.
The more immutable (less mutable) your app, the faster it is.
The 'Home!' example app is demonstrated in the video on your the right.
With every press of the button, indeed the whole screen is rebuilt.
This is just like the traditional Counter app that's created with every new Flutter project.
The build() function for the _HomePageState class is called again and again with every tap.
However, in this example app, the items displayed in red are updated independently of the whole screen rebuilds.
They are updated only when changed leaving the rest of the screen untouched (highlighted in second screenshot).
Build Change
The series of greetings, for example, change with every five taps of the button.
Only that area of the screen changes.
Further, as the count increments, you'll notice the red counter also increments to keep up with the current count.
It then starts over when the current count is reached.
Stop pressing the button, and the red counter continues the loop.
Again, only that region of the screen is updated.
The rest of the screen is left unchanged. Very efficient!
There is no 'rebuilding of the whole screen.'
The less the interface is changed at any point in time, the better the performance.
Updating the app's interface, in most instances, is the most 'expensive' operation.
Spontaneous Rebuilds
The first screenshot below highlights the two widgets that displays those two items in red.
The widget, `timer.counter`, involves a timer incrementing up to the current count.
The StatelessWidget, `SetState`, supplies a builder callback routine that's called again only if the App's 'InheritedWidget' is called again.
That's because this `SetState` widget has been assigned as a 'dependent' to that InheritedWidget.
This is a powerful aspect of using InheritedWidgets allowing for sporadic and spontaneous rebuilds of only parts of the interface
(see:
dependOnInheritedWidgetOfExactType()).
The second screenshot is a closer look at the `SetState` builder passing the current greeting using the property,
dataObject.
Depend On Time
The first screenshot below highlights the timer class being instantiated and then added to the StateX object,
_HomePageState.
The second screenshot conveys the getter, `counter`, found in that timer class. Depending on whether the current count is an odd number or not, another `SetState` widget is utilized when incrementing the count.
Otherwise, a StatelessWidget called,
_TheCounter, is called to demonstrate how the App's InheritedWidget
assigns a widget as a 'dependent' using the AppStateX's function,
dependOnInheritedWidget().
The Root of Inheritance
The
_TheCounter StatelessWidget is displayed in the first screenshot below.
Highlighted is the 'root' State object taking in this widget as a dependent through its context.
Now, every time that InheritedWidget is called again, the
build() function below is also called.
Note, the timer class extends the
StateXController class, and so has the
rootState property
with its
dependOnInheritedWidget() function.
Thr second screenshot is the SetState widget.
It too has the 'root' State object in its build() function calling the dependOnInheritedWidget() function.
And so, when the app's InheritedWidget is called again, the builder callback routine is called again.
See how that works?
Notify of Change
The screenshots below depicts how the Timer object is instantiated and set up.
Note the
_increment() function in the second screenshot calls the 'root' State object's
notifyClients() function,
and this means the app's InheritedWidget is called again as well as all its dependent widgets.
Control Events
Adding controllers to StateX objects allows those controllers to react appropriately when the app is placed in the background,
for example, or when the app is terminated. It is especially important in this "Hello!" example app as a Timer is involved in the operation.
Such a timer would continuously run even when its not necessary.
For example, this Flutter app can easily be found running on a mobile phone.
With that, such an app can routinely be interrupted by the user switching to another app,
answering a phone call for example, and then return to the app.
The StateX class has some twenty-six (26) event handling functions available to you
to take into account the many external events that can affect your running app.
In the case of the "Hello!" example app, there is a ready means to stop the Timer when the app is
placed in th background as well as start the Timer up again when the user returns and the app resumes its operations (see right).
This is great news since Timers and operations like it simply take up resources,
and if you don't do anything about it in the first place,
your app will soon be labeled a 'memory hog.'
Time to Initialise
In the screenshots below, we have the screenshot again of the Timer class being instantiated
and then added to the StateX object,
_HomePageState.
Adding that controller now means, when the State object's
initState() function is called,
the
initState() function in the controller,
CounterTimer, is also called.
Every controller added to the StateX object will have its
initState() function called.
The second screenshot is that of the CounterTimer class.
You can see it's in its initState() where the Timer is first initialised with the initTimer() function.
It's there where the Timer begins keeping tabs on the current count. When that count increments, the Timer will keep in-step.
Pause for Time
Now in the screenshots below, you see how the timer is stopped and started again depending on the circumstance.
A controller class is provided an assortment of functions to address particular events.
As you can readily see in the first screenshot below of the CounterTimer class, when the running app is placed in the background, for example,
the
pausedLifecycleState() function is called. There, the Timer is turned off.
When the app is returned focus, the
resumedLifecycleState() function is called and the Timer is turned on again.
The second screenshot displays the didChangeAppLifecycleState() function in the StateX class.
As you see, the didChangeAppLifecycleState() functions of any and all the controllers it may contain are also called.
Next, however, functions dedicated to specific cycle events are then called.
You can see where the pausedLifecycleState() function and the resumedLifecycleState() function are situated.