The State of Flutter
By: Greg Perry
Tags: Mobile App Development, Android App Development, Software Development, Flutter, iOS App Development

See The Abstract

You can see the Bloc object referenced here and there in the build() function providing the data and the event handling pertaining to the data. Now, how is that ‘Business Logic Component’ obtaining ready access to the rest of the app? More specifically, obtaining ready access to the State object, _RandomWordsAndroid, in this example? Well, you can see, _RandomWordsAndroid, is a subclass of the class, _RandomWordsState. Below is a full screenshot of that class.

It’s easy enough to see that, when the Bloc is instantiated, it’s merely passed an instance of the State object, and there you have it — your business logic now has access to the State object. Those observant readers will also note the leading underscore. Hence, the class still remains in the same Dart file. Again, larger more complex apps would likely warrant the Bloc code in a separate Dart file, but since this is such a simple example, please forgive my discretion for now.

Please, also don’t think I’m involving the BLoC design pattern here when I use of term ‘Bloc’. The term is used here to describes how to represent the ‘logic’ or, dare I say it, the ‘state’ of this part of the app separate from other aspects of the app. Although such a separation is indeed found in the BLoC design pattern, the term ‘Business Logic Component’ stands on its own. IBM, for example, was using the very term when e-commerce was in its infancy.

The Data From The Interface

One common trait you’ll find in a desirable design pattern is the separation of the app’s interface from everything else. Further, there should a degree of abstraction involved in this separation. And so, in this simple example, ‘how the data is displayed’ is separated from ‘what data is displayed.’ Further, you’re likely very familiar with the Write your first Flutter app example, and yet looking at the stretch of code below, you’ve no hint that the app is, in fact, listing Word pairs with trailing little hearts. That fact is concealed with a degree of abstraction.

Separate the app’s interface from everything else. There should a degree of abstraction in this separation.

Shows the How Not The What

What you do see is that whatever is being listed is being separated by a Divider widget and is displayed rather large with a font size of 25, but that’s about it. However, that’s a characteristic we’re looking for in a design pattern. For example, when it comes to the interface aspect of this app, that’s enough information to know. The common traits I’m talking about, today, involves the separation of responsibilities. It also involves a ‘degree of abstraction’ in how the separation is performed— such an approach will make for better development, better maintainability, and a better app. I’ll explain further.

Note, the property names of the Bloc object in the ListTile widget. Now, those names weren’t arbitrarily picked out of a hat. The last two highlighted with arrows, for example, were named after the named-parameters in the ListTile widget while the property, bloc.data, is named after the positional parameter found in the Text widget. Frankly, the function, bloc.build(), could have been named, bloc.builder(), to follow that trail of thought, but the word, build, is versatile enough to then work with other widgets, no?

Below is a screenshot of the Bloc highlighting its API used by the interface. The interface doesn’t know what it’s listing, (i.e. low coupling) but it does know what API to use to list it. The screenshot reveals the true ‘state’ of this part of the app — it reveals what sort of data is actually being listed. The degree of abstraction used by the Bloc class with its ‘generic names’ for specific getters and functions is a conscious effort to put in place a consistent application programming interface (API) so possibly other interfaces can readily work with this Business Logic Component. The Flutter framework’s very own API (the names of its parameters and functions) is used as a guide.

Access The State

So, as it happens in this particular example, the Bloc itself (the app’s logic) now ‘retains the state’ for this aspect of the app. When instantiated, the Bloc took in as a parameter, a State object. The reference to this State object primarily serves to call again and again the declarative code found in that State object’s build() function — so to convey the ‘current state’ of that State object at a given point in time. To call that declarative code, of course, the logic merely has to call the State object’s setState() function.

There’s an example of calling the setState() function in the screenshot below. It shows what happens after the Bloc object responds to a ‘tap’ event. The user taps on one of the little heart icons saving the selected WordPair, and the Bloc’s onTap() function performs the operation. Of course, the interface doesn’t know that. Note, the class, _DataBloc, extends the class, Bloc. We’ll take a closer look at that class next.

Be The State

When dealing with the Bloc, because it has access to the State object when first instantiated, you can use this Bloc as you would a State object. You certainly have access to the ever-important setState() function. In fact, there are four functions that essentially perform the same thing. They merely vary in name depending upon personal inclination frankly. This is another example of a degree of abstraction implemented in this approach. It’s an attempt to make the Bloc class the solution to all possible circumstances and preferences.

Because the Bloc object has reference to the State object, it has further access to the State object’s own properties: widget, mounted, and context. Imagine what you can do with those properties in your separate logic?

The State’s Logic

Again, the more observant readers will have noticed this version of the example app is using a subclass of Flutter’s State<StatefulWidget> class. I’ve called it, StateBloc, in recognition that it works with the class, Bloc, to supply a State object to a business logic component.

This StateBloc class allows the developer to access the State object’s StatefulWidget using the property, widget, as well as the setState() function of course. However, more specifically, it allows its Bloc counterpart to gain access to it.

Don’t Block This Class

Below is a screenshot of the whole Dart file that contains the classes, Bloc and StateBloc. Now I’m not advocating you use these two particular classes in your projects. I’m certainly not supporting this Dart file. I just whipped it up to demonstrate the topic at hand. I’ve got my own framework package for my apps — it has the characteristics described here, of course, and more. Yeah, I meant it when I said I wasn’t thrilled with the ‘State Management’ solutions offered two years ago. So much so, I wrote another one to put it in the mix.

No, if anything, I invite you to take this ‘Bloc’ class and see how it works. You see, such a Bloc/Controller isn’t any good if it can’t work with other parts of your app — in other parts maintaining their own state/data for instance. You see, the Bloc class below allows for a Bloc object to work with more than one State object as your app goes down its widger tree. In other words, you can add the same Bloc object to more than one State object. Neat stuff.

Of course, your app could also have more than one separate and distinct business logic component altogether. For example, one could be for just the app’s ‘home screen’ and all the logic that entails while another one could be concerned with the general ‘look and feel’ of the app as the whole.

Pick Your Platform

As an example, you’ll notice in the revised version of Write Your First Flutter App, there’s a double-arrow icon up on the navigation bar in the left-hand corner. Clicking on that icon allows the user to switch back and forth between the Material and the Cupertino interface design — between Android’s offered interface and iOS’s recognized interface.

A separate State object is involved in this particular operation. Further, by design, there’s a separate and distinct Bloc that helps the user with accessing that State object — as well as, more importantly, retaining which interface design is currently being used. Note, the Bloc is named _AppEventHandler, and it too displays the same two characteristics highlighted in this article: A separation of responsibility with a degree of abstraction in its API.