A Better Flutter App #8

I Like Screenshots. Tap Caption For Gists.

As always, I prefer using screenshots in my articles over gists to show concepts rather than just show code. I find them easier to work with frankly. However, you can click or tap on their captions to see the code in a gist or in Github. Tap or click on the screenshots themselves to zoom in on them for a closer look.

No Moving Pictures, No Social Media

There will be gif files in this article demonstrating aspects of the topic at hand. However, it’s said viewing such gif files is not possible when reading this article on platforms like Instagram, Facebook, etc. They may come out as static pictures or simply blank placeholder boxes. Please, be aware of this and maybe read this article on medium.com

Other Stories by Greg Perry

Individual Change

You can see in the build() function below, the CounterController controller’s class property, wordPair, is being displayed. In the gif file, you readily see it corresponds with the red word-pairs changing every few seconds. What if I told you the whole screen is not being repainted (rebuilt) with every word-pair change? In fact, what if I told you only the property, con.wordPair, is being rebuilt? It’s the only Widget where its build() function is being called. Further, what if I told you it’s only being called when a new word-pair is generated?! A wonderful bit of efficiency! The rest of the screen is left alone and unchanged. It’s an isolated and separate rebuild of one small Widget located on the screen, and I’ll show you how this is implemented by the framework and used in the starter app example.

Get A Pair

Back in the initTimer() function where the Timer is first created, a duration and a callback function is provided. The duration in the starter app is explicitly set to two-second intervals when the app is first started. The callback function, if not explicitly assigned from a parameter, is assigned the function, _getWordPair(). At the end of every interval, the Timer object will call this function generating a word-pair. And so with every newly generated word-pair, you can see in the second screenshot below it is then assigned as a String object to the static variable, dataObject.

Built It And They Will Too

However, know this. When that static variable, dataObject, is assigned a value, an underlying State object in the framework that has its own InheritedWidget is having its setState() function called — calling that InheritedWidget again. Doing this will cause every and all of that InhertiedWidget’s ‘dependencies’ to call their own build() functions — resulting in the dispersed and separate rebuilds of those Widgets as well. A powerful feature of InheritedWidgets! As it happens, in this framework, any and all SetState widgets are dependent on this InheritedWidget by default. Therefore, with every assignment of a value to the Static variable, dataObject, any and all SetState widgets used by the app will also be rebuilt. Follow me so far?

A Stateless State Set

And so, as you watch the word-pairs go by in the gif file below, know that the build() function of the StatelessWidget below is being called with every new value assigned to the static variable, dataObject. Easy peasy. That one little getter, wordPair, thus displays a new value every time — leaving the rest of the screen unchanged. Even the Counter app that hosts this getter is less efficient! Every tap of that button causes the whole screen to be rebuilt! A waste!

Inherit The Widget

In this alternative approach, let’s take out the SetState class altogether for the getter, wordPair, and replace it with a StatelessWidget called, _WordPair. Indeed, in the second screenshot, this StatelessWidget returns the Text widget with assumingly the next generated word-pair assigned to the class property, con._wordPair. Note, an inheritWidget() function is called just before the Text widget is returned. To make any Widget a ‘dependent’ of the framework’s InheritedWidget you need only pass its context to this function. It’s essentially the very same thing as what you may be familiar with when working with InheritedWidgets and instead issuing the following command: context.dependOnInheritedWidgetOfExactType<_InheritedWidget>();

Inherit The State

Ok, so what else is required. Well, the SetState approach required some static variable to explicitly be assigned a value causing the framework’s InheritedWidget to then be rebuilt. Well, what if you just want to explicitly call the framework’s InheritedWidget to rebuild yourself? —you just want its build() function to run again when you want to? I mean, it’s your app! You’re responsible for calling the InheritedWidget and consequently all its dependent Widgets’ build() functions. How would you do it in this scenario?

word_pair_timer.dart

Pass the Build

In the first screenshot below, that fourth line is now uncommented. It reveals it’s the same inhertedNeedsBuild() function but with the instance variable, _wordPair, passed to it. Now looking in the second screenshot at the further modified StatelessWidget, _WordPair, you’ll discover the passed variable was assigned to that static variable, dataObject. Thus, this is another means to have that static variable come into play if you wish. Bit of overkill in this simple example, but you do have that option.

Same Inherited Behavior

All this results in the same behavior. In this case, the InheritedWidget is explicitly called to rebuild using the function, inheritedNeedsBuild. Any and all Widgets with the function call, inheritedWidget(context), in their build() function will then be rebuilt. That’s the most powerful aspect of Flutter’s InheritedWidget!

shutterstock
Part of the ‘A Better Flutter App’ Series

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store