MXC before MVC

Greg Perry
Follow Flutter
Published in
19 min readMar 15, 2019

A Flutter framework for before AndroidX!

Working away on my MVC framework package, I realized an important issue had come up that would have to be addressed. Everything was coming along nicely, but…

Other Stories by Greg Perry

Then Came AndroidX

With the release of Android 9.0 (API level 28) there came a new version of support libraries under the banner, AndroidX. These versions are incompatible to the earlier plugins and packages used by Flutter and consequently by the MVC framework package I would soon be releasing. And so, in the interest of the Flutter community, I decided on something about it.

MVC_Application With An X

I decided to deliver a ‘pre-release’ of the framework package. One that will still work with the now deprecated and yet currently more widely used support files. While the standard package, mvc_application, will continue on with the most recent and future Android support files, this release will only work with the support files available prior to AndroidX. I decided to call it, mxc_application. With its subtle ‘play on words’ this will be an early release of the ‘MVC framework package.’

Keep Your Versions

Thus, this version of the framework is everything like the MVC version I’ll soon release, but for one important distinction. One that’s reflected in the list of versions numbers found in the framework’s pubspec.yaml file. They’re all the old versions of the plugins and packages that worked prior to the migration to AndroidX.

pubspec.yaml

NNNote, this particular framework package will not progress any much further in development. After all, it’s only really helpful to those developing apps for the Android platform using deprecated support library files that will one day go away.

A Quick Start Up Guide

This article will serve as a primer to the main release of the framework. Again, the ‘pre-release’ offered here will provide much of the same functions and features of the main release. A main release that’s yet to be released frankly. In this article, to demonstrate these functions and features a sample app will be used. Many of my readers has seen this sample app before in past articles. Here is it’s repository: Contact AndroidX Example

AAAs always, I prefer using screenshots over gists in my articles to show code. I find them easier to work with, and easier to read. However, you can click/tap on them to see the code as a gist or in Github.

Let’s begin.

Supplementary Sources

First and foremost, you may find reading these two other articles before or after this one helpful in understanding how and why you would use this framework package for your apps.

One is a past publication that introduces you to my interpretation of MVC and how it would take advantage of Flutter’s own framework. It presents the ‘core’ Flutter package, mvc_pattern, which directly implements MVC in Flutter:

Flutter + MVC at Last!

The second article, Flutter Faster!, will delve into the MVC implementation even further and present you with some approaches you may find useful in your own apps. It too will give you some good background on how one would use this MVC framework.

NNNote, some of the framework code covered in that particular article has since changed and is now deprecated frankly. A good sign that this library package continues to evolve and be supported. It’s still a recommended read however.

Flutter Faster!

Three Things

There are three things you do to use this framework:

1) Extend the class, ControllerMVC, and then use that class to contain the app’s ‘logic and event handling.’
2) With every StatefulWidget in your app, don’t use a regular State class, but extend the class, StateMVC, and use that class as the State object.
3) ‘Add’ the Controller to its appropriate ‘StateMVC’ State object.

I’ll explain each step with examples and screenshots shortly. But first, I’ll step back and quickly explain ‘why’ would you involve such elements.

Why ControllerMVC?

The controller is one of the three players involved in the MVC architecture. In many apps, Controllers are the ‘work horse’ of source code the majority of which contains the ‘business logic’ or ‘the brains’ of the application.

Keep It Immutable

Have you ever noticed how the compiler will complain if your variables, for example, are not final in your StatefulWidgets? It’s a warning, and you could get away with it, but it’s bad form. Immutability certainly has its benefits, and maybe we’ll discuss that another time. For now, however, I’ll demonstrate such a warning. See the screenshot below?

AddContactPage on Github

When I remove the keyword, final, from one of the property variables (or instance fields as Flutter calls them), we then get that warning:

You Should Be Immutable

Again, you can do it, but you shouldn’t. However, in most cases, there’s going to be code that needs to be mutable. So what can you do? Utilize the MVC architecture of course. By design, the Controller can be mutable, and you can have many of them. That’s why we have the class, ControllerMVC.

So below, there are some private variables that are mutable. They’re found in the ‘Controller’ for this sample app, and of course, there’s no complaints.

class Controller in Github

Why StateMVC?

In this interpretation of the MVC, I’ve decided that the build() functions found in Flutter’s State objects would serve as ‘the View’ for the Model-View-Controller architecture. So, State objects contain ‘the View’ for an app. Another reason I chose the State class was due to the face that they are also capable of ‘observing’ the many different events that may occur during a typical Widget’s lifecycle. In other words, there’s a means to ‘listen’ for such lifecycle events with what are called, observers. Observers are a characteristic of the MVC architecture.

MVC = Observer Design Pattern

MVC is an architecture that uses the Observer Design Pattern. It involves the implementation of ‘observers’ or ‘listeners’ that are notified when a particular event happens. Again, the State object is capable of having ‘listeners’ that, in its case, can observe the Widget’s lifecycle. A useful ability. Hence, that’s why we have the class, StateMVC — the MVC State object.

initState() function in StateMVC

The screenshot snippet above is only the first few lines of the MVC State object’s initState() function. Note the last line there referencing the class, WidgetsBinding. As described in its source code, this is ‘The glue between the widgets layer and the Flutter engine.’ It gives us the means to access the many events that may occur during the Widget’s lifecycle. Turn to the WidgetsBindingObserver Class for more details.

Last Step: Add The Controller

Assigning the Controller to the MVC State object that contains the View attains the Controller some important abilities. Again, looking at its initState() function above, we see the MVC State object has access to the Widget’s lifecycle. However, if you were to add or assign a Controller to that MVC State object, then that Controller will have access the Widget’s lifecycle as well. Very useful.

The Mixin Does The Listenin’

It’s the mixin, StateListener, that is used to ‘listen in’ on up to twelve events (and more with every new version of Flutter) that may fire during a Widget’s lifecycle. It’s an important element in this MVC framework.

mixin StateListener in Github

You can see below, that a Controller (i.e. A class that extends ControllerMVC) will use the mixin, StateListener, through the inheritance of the private class, _StateObserver. Note, you can use the StateListener on its own as well.

class ControllerMVC in Github

Make note, the function, addState(), found in the abstract class, ControllerMVC, implies the ability for a Controller to be assigned to any number of MVC State objects during its lifecycle. Another important and useful ability.

Note further, with the getter, stateMVC, provided to the Controller through the class, _StateObserver, consequently allows the developer direct access to the MVC State object last assigned to the Controller. Very Nice.

The State Also Listens

In fact, the MVC State object itself ‘implements’ the StateListener. Thus requiring the abstract class, StateMVC, to implement the 12 (or more) event functions which the StateListener mixin contains.

class StateMVC in Github

Note, the build() function is not implemented and is commented: The View! That is why StateMVC is an abstract class. It must be subclassed and its ‘View’ (i.e. its build() function) implemented.

In Review

So, in review, there’s three things you need to do so you can use this MVC framework. The sample app demonstrates these steps with the three screenshots below. Their captions are detailing each step.

Create a class that extends the class, ControllerMVC
Create a class that extends the class, StateMVC, to serve as the MVC State object.
Assign the Controller to that MVC State object.

The MVC Framework

I had the MVC approach implemented and supplied by the Flutter package, mvc_pattern, but there was more to be done. There’s a lot to even a simple mobile application, and I was writing both simple and complex ones in my work. There was a lot of the same processes and tasks needed to be performed when these apps started up. A lot of the same functions and features were commonly found in all of them. With every new app I developed, writing these common tasks and features over and over again would be very inefficient if not down right idiotic. I needed a framework. So I made one, and that’s what we’re reviewing here, today.

How To Start It All?

So, how do you start up this Framework? Well, of course, you include the MVC Framework package, mxc_application, in you app’s pubspec.yaml. You know that. However, what happens in your app’s main() function?

You’ve got options of course. The function, main(), with its traditional call to the function, runApp(), can either take in the class, MVC, or the class, App. Either will do with one important difference. With the class, App, you’ve got the ‘App Controller’ option and with the class, MVC, you don’t. I’ll explain that shortly. Meanwhile, below are two screenshots demonstrating the two ways of starting the sample app.

File, main.dart, with Two Different Approaches To Start

The Framework’s Own Model-View-Controller

Like the Flutter package, mvc_pattern, with its MVC architecture, this framework also deals with Models, Views, and Controllers. In the sample app, the class, ContactsExampleApp, is the ‘App View’ for this mobile application. Looking at both the class, MVC, and class, App, below respectively, you can see the ‘App View’ parameter in both cases is of type, AppView, and is a required parameter.

It turns out the class, MVC, will simply instantiate the class, App, anyway. However, note the second parameter, con, of type, ControllerMVC, is completely overlooked in the class, MVC, when it instantiates the class, App.

As an aside, looking at the class, MVC, you readily see that the class, App, is instantiated in the function, build(). Of course, this tells you the class, App, is a Widget of some type. That would stand to reason since the class, App, could also be passed directly to the function, runApp().

Options! Options! You Have Options!

As you see in the screenshot below, three options were supplied to the ‘App View’ to be used by this particular sample app. In most cases, these three would be the most common options used. However, as you see in another screenshot of the class, ViewMVC, far below, no less than 23 options are available to you. As you become familiar with this framework, you’ll discover all those options are concerned with the general behavior and appearance of the app as a whole.

class ContactsExampleApp on Github

Follow Your View

Let’s take a deeper dive at this point to get a better understanding of this MVC framework. From the beginning, in the main.dart file, again we see the ‘App View’ class, ContactsExampleApp, being instantiated and passed into the framework.

main.dart on Github

From there, we arrive in the class, App. There, the framework performs a number of tasks in preparation to start up. Looking in the build() function below, you see things are being initialized with calls to functions literally called, init().

class App on Github

There’s a FutureBuilder() used here. Until everything has been initialized and ready to go on, a ‘loading screen’ (a circular pattern rotating in the middle of the screen) is displayed. However, when there’s data, the app is ready to go, and the widget class, _AppWidget, is then instantiated.

Its Your State

Going now into this widget class, _AppWidget, we see that it’s of type StatefulWidget, and that, in fact, our ‘App View’ is obviously a State object. After all, it’s being returned by the createState() function. Listed beyond it is the class, AppView. The class our ‘App View’ extends from.

class AppView on Github

The Material of View

Further on in the class, AppView, we see the build() function returns the class, MaterialApp. In fact, it is in this class that many of those 23 options mention earlier are passed as parameters into the MaterialApp constructor.

class MaterialApp in AppView’s build() function

It All Comes Around

Note, if you go further down the class hierarchy of this ‘App View’ and arrive at its parent class, AppViewState, you see that it, in turn, extends the MVC State object, StateMVC — containing a View. See how it all comes back to the three components that make up the MVC architecture?

class AppViewState in Github

Back To MVC For The App Controller

Note, back in the class, AppView (see below), the ‘Controller’ passed into it is not of type, ControllerMVC, but of type, AppController. Stands to reason. It is the ‘App Controller’ after all. Let’s see where this takes us.

class AppView on Github

The App Controller Prepares The App

As you would have guessed, the class, AppController, extends the class, ControllerMVC. It’s short in length but long in importance. The screenshot of the class, AppController, is below, and you see that it’s responsible for much of the common tasks involved in preparing a typical mobile app when starting up — those tasks can bee seen in its init() function.

class AppController on Github

It’s initializing the Prefs library, responsible for storing and retrieving the app’s preferences. It initializes the DeviceInfo class. This class is responsible for providing up to 32 separate bits of information regarding the phone‘s hardware and its software. This information is then made available to the developer.

Cleans Up After Itself

In its dispose() function, you see the ‘App Controller’ is also responsible for ‘cleaning up’ after itself as well when the app shuts down and terminates.

Your App Within The App

So we set up the app, and now we’re ready to display the ‘home’ screen to the user. Below is the screenshot of the ‘App View’ for the sample app with its three common options provided. You’ll soon realize it’s an app within the app. We’ll now look that this home screen with its own StatefulWidget and consequently its own StateMVC object (the View), its own ControllerMVC object (the Controller) and even its own Model. You’ll discover the MVC architecture is again implemented as the guts of the particular app.

class ContactsExampleApp on Github

Let’s Go Home

And so, here we go again. Below is a screenshot that displays the Widget and its MVC State object containing the build() function— the ‘View’ for this sample app. The code beginning the MVC State object, _ContactListState, lists most of the players involved. There’s a Controller unimaginatively named, Controller. Of course, there’s the MVC State object itself, and the Controller is then assigned to that MVC State object. With that, we’re well on our way. Next, to the heart of this sample app — its build() function.

class ContractListPage on Github

You can see the build() function is characteristically peppered with references to the Controller — highlighted with red arrows. This is where the Controller supplies the View with data or to response to events. In some spots, the Controller even inserts additional Widgets that displays data and or to response to events. A separation of responsibility is in here. Very nice.

Reference Control

Notice you have the option to retrieve a reference to the Controller once the MVC State object has taking it in. There’s a field instance of type, ControllerMVC, called, controller, in the MVC State object. Below, it is assigned to the variable, con, of type, Controller. Doing so, you then a true reference to your Controller with its own field properties and functions. Nice.

class _ContactListState on Github

Note, its really not needed in this sample app since, as you can deduce, this Controller class is presenting all its data and widgets through static fields and static functions, but again, you have that option. For example, looking at the screenshot below, you see that that reference is used in one spot — to list out the Contacts for this sample app:

ListView.builder() in _ContactListState on Github

Where Does It Really All Start?

Below is the ‘App State’ for this framework. It’s a MVC State object, and when this framework starts up, it is here where the startup process really begins. And so you can see, like a standard Flutter app, the initialization process starts in the State object’s initState() function. Let’s do a walkthrough.

class _AppState on Github

If we step into the function call, widget.initApp(), we arrive in the class, App. Below, you see the first portion of the class, App, and it’s initApp() function that was just called. You see in there a ‘App View’ object with the field property, con. You’d be right if you guessed this was the ‘App Controller.’

class AppMVC on Github

But First An App AppController

Note, however, the initApp() function from the parent class is first called. The parent class is the class, AppMVC. The beginning of that class is listed below displaying the corresponding initApp() function. It too has its own Controller if you remember. The one overlooked by the MVC class in the main.dart file.

However, if you used the App class instead in the main.dart file, you had the option of passing in yet another Controller. One to be the first Controller actually run when initializing the framework. For what purpose? Frankly, for any purpose you dream up depending on your circumstances. Love options!

class AppMVC on Github

A Controller With An Init

The class, AppController, implements the class, AppConMVC. This installs the two ‘init’ functions, initApp() and init(). As you see below, the init() function is fully utilized in the start up process with calls to the class, Prefs and DeviceInfo. However, the function, initApp(), listed above and called in the initApp() function for the class, AppMVC, is left empty. This is for developers to use if and when they need to initialize ‘small synchronous’ operations.

AppController on Github

Init The Future

So the AppController’s initApp() function is called starting from a State object’s initState() function. That’s good. Now where is the init() function with its Prefs and DeviceInfo called? It’s called in that FutureBuilder(), remember?

See below, in the class, App, it’s build() function returns a FutureBuilder. That FutureBuilder has a named parameter called, future. Surprise, surprise. The function there, init(), has to return a ‘Future’ boolean value. In other words, until everything is initialized, no snapshot.data is available, and only the loading screen will be displayed. Clear so far?

class App on Github

Just above, you can see the init() is calling the corresponding init() from its parent class and then (when its ready) it calls the ‘App View’s’ own init() function. See how it works? Look below, and you’ll see what’s involved in the call, await _vw.init() — the ‘App View’s’ init() function.

class AppView on Github

Ironically, it makes two static function calls back to the class, App, itself. Let’s see what the function, _initInternal(), does for this framework.

_initInteral() in class App on Github

Again, the idea for all this is to get things ready. It’s to supply all the necessary information about this particular phone, and in the case of this function, all the information about this particular installation of the app itself.

In the _initInternal() function, we acquire a ‘installation number’. This is a number uniquely identifying a particular install of the app. A developer, for example, can then record that value it their remote databases for some marketing campaign or some other diabolical scheme. *chuckle*

It further retrieves the location of the app’s database location on the phone as well as determines how the phone is currently connected to the Internet. To what purpose you ask? Only the developer in need of such information would know. The point is it’s there if they need it.

After the _initInternal() function there is another call to get further ‘platform’ information which will then be readily available to the developer. However, it’s the next call, to the parent class, that I want to show you now. It takes us to the class, AppViewState, and its init() function. There, we see it calls the init() function from the Controller that it had taken in. See how things work? Again, it always involves the three components of MVC.

class AppViewState on Github

With Some Tools To Boot!

Using this library package will privy you to a couple of tools as well. It is its own Flutter package, Prefs, but I’ve inserted it directly into this package for better ease of use. The other involves creating and manipulating SQLite databases. It’s is own class library, but again, inserted directly into this Framework for easy access. These are tools I use all the time. Might as well have them readily available, right?

Flutter and a SQLite Database

Add Ads In Your App!

Also available as of this writing is yet another Flutter Package, Ads. This very useful package will allow you to easily incorporate Ads into your own Flutter app. Note, you do have to work with Google Adsense and get an ‘AdMob id,’ but then you’re own your way to monetizing your app!

Ads Flutter Package

A Class Of Your Own

Remember how it it turned out the class, MVC, instantiates the class, App, anyway, but completely overlooks the second parameter, con, of type, ControllerMVC. See below. So anyway, if you wanted to, you could supply your own ‘App Controller’ by using the class, App, in the file, main.dart. One where you can then implement its initApp() function and or its init() function if you need to ‘initialize’ heaven knows what before your app presents itself to the user. Otherwise, use the class, MVC , and a ‘default App Controller’ would be supplied instead. Note, in most cases, you’d use the latter and be content with the ‘default App Controller,’ but you’ve the option. You know how I love options.

How Now App Controller?

So, just for your reference, how would a ‘default App Controller’ come about with the use of the class, MVC, in the file, main.dart? Well, it doesn’t. It comes about with the use of the class, ViewMVC. As you see, the class, ContactsExampleApp, extends the class, ViewMVC.

class ContactsExampleApp on Github

Below is the class, ViewMVC. It is the ‘View’ for a MVC app, and in particular for this sample app. It is the parent class to the class, ContactsExampleApp. It is this class, if and when no ‘App Controller’ is specified, that provides one by default.

class AppView on Github

Prep Your Own Controller

And so, in review, going back to the two ways of starting up an app with this MVC framework. If there were some additional preparations necessary for your particular app that’s needed to be performed way before its displayed to the user, there was a means to do this. You would simply provide your own ‘App App Controller’ by extending the class, AppController, overriding either the initApp() function or the init() function depending up whether these were synchronous or asynchronous operations, and you’re then good to go.

As an example, below is a snippet from one of my own projects, where I required an ‘App App Controller’ be made and passed into the MVC framework. You can see, in this app, additional operations ‘to the cloud’ were required before the user was presented the app. I utilized the function, init(), and the standard State object function, initState(), for this purpose.

class WorkingMemoryApp on Github

Note The Lifecycle

As you see in the screenshot above, I further utilize the App Controller’s ability to respond to Lifecycle events that commonly occur in a Widget. I do so with the use of the function, didChangeAppLifecycleState(). Neat stuff.

Wait For It

I’ll conclude this for now. Again, this release is only for a particular audience. Those Android developers still using an API level less than 28 (Pie) frankly. The general MVC framework package will be released soon. As it happens, this “MXC” release may be supported for a time with pull requests and such if there is a need for it, but it’s really the release of the general MVC framework package, mvc_application, that I’m looking forward to.

Cheers.

→ Other Stories by Greg Perry

DECODE Flutter on YouTube

--

--