A Better Flutter App #1
Allow your Flutter App to get set up and ready to go at startup
One of a series of articles detailing a comprehensive starter app. This app is generated by a template offered by the package, app_template, which uses the underlying framework, mvc_application, based on the MVC design pattern.
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
Hurry Up and Wait
Look at the two gif files below. Note, there’s a black screen and a blue circular spinner coming from the ‘better’ starter app. That circular spinner comes about because there’s some work that needs to be done before the starter app is ready to continue. The original starter, being so simple, has no need for such a mechanism. However, that’s certainly an exception and not the rule for a typical Flutter app.
In the case of the better starter app, there’s an SQLite database to be opened and made available for the user before the app can continue. Note it could be any sort of ‘time-consuming’ process that must be performed before the app is ready for use. You need the means to do this at startup.
I would say, it’s one of many critical features needed of any Flutter app you develop, and in this article, I’ll show you how this starter app uses the underlying framework, mvc_application, to open and ready its SQLite database, and how easily this framework allows you to implement such operations.
Start-Up With Some Background
If you open the main.dart for this starter app, you’ll find essentially only one line. It’s where the main() function calls the function, runApp(). You can see it in the screenshot’s inset below. The rest of the screenshot is of the class, TemplateApp, that’s called and passed to the runApp() function.
You’ll note in the screenshot above that the class, TemplateApp, extends from a class called, AppMVC. This is the base class for every Flutter app using this framework. Like a StatefulWidget, it too requires the developer to override its createState() function and return, in this case, the ‘App State object’ — unsurprisingly, the class returned is of the type, AppState.
Ironically, as you see above, the AppMVC class actually extends Flutter’s StatelessWidget class and not its StatefulWidget class. The createState() function could be a little misleading, but it’s a StatelessWidget because its role does not require it to retain a state. However, its build() function does perform one very important operation. It uses a FutureBuilder widget to get the app set up and ready to go before allowing it to continue. See below.
We won’t get into all the details of this framework here. Just know the initAsync() function highlighted above is responsible for getting the app up and running and ready for the user, and until that’s accomplished, a circular spinner is presented on the screen called by the _asyncBuilder() function.
Now a number of operations occur in that initAsync() function. One of which is to call the initAsync() function found in every ‘App Controller’ class object supplied to the framework at startup. Looking back at this article’s first screenshot, there appear to have been three ‘App Controller’ class objects supplied to the framework at startup; one of which opens the Contacts database — and opening a database can sometimes be a time-consuming operation. See below.
Looking at the ContactsController class below, we see that it indeed extends an AppController class and instantiates the Contacts database into a variable called, model. Once instantiated, the database of course must be opened before it can be accessed.
Further along in the ContactsController class, you’ll find its initAsync() function. It’s there where the database is opened and indeed queried to retrieve any and all contacts information using the function, getContacts().
As you can see, if everything goes as intended, this function returns a boolean Future object with a value of true. Doing so will alert the framework that the app is now ready to continue. Are you still with me?
Control The State
A controller for every State object is a design pattern commonly found in this framework. You may have noticed by now that every State object used in this app is a subclass of Flutter’s own State class and is called, StateMVC. Unlike the State class it extends, the StateMVC class has one optional ControllerMVC parameter. See below.
In the case of this app, the controller object, ContactsController, is responsible for opening and accessing the Contacts database. Passing that controller object to the StateMVC object, _ContactListState, allows that database’s contents to then be displayed. See below. Again, however, but not before the database is opened and is ready to go.
And so, as I stated earlier, deep in the framework all the ‘App Controller’ objects instantiated at the start of the app each have their initAsync() functions called in turn (see below). There can be as many as you like completing as many operations that are necessary before your app is ready to continue.
Until the app is ready, the user is greeted with a spinning graphic or a loading screen if one is specified. Looking back at this article’s second screenshot, you can see such a loading screen can be passed as a parameter to the AppMVC class.
So there you have it. It’s an important part of any app written today. You have to give the app the means to get set up and ready for use upon startup. The starter app details how this is easily accomplished using this framework.