An MVC approach to Flutter
Dated: 2018–03–28
The other day, I typed “Flutter” “MVC” into Google (quotes gives you a ‘Verbatim’ result), and got the typical suggestions to use third-party libraries. They do have their place, but I just wanted to implement such a design pattern in a few ‘native’ classes — in keeping with the good ol’ ‘KISS principle.’

As you know, like other design patterns, MVC aims to decouple its three major components allowing for efficient code reuse and parallel development. Like most things, it generally ‘makes Life easier’ if you break things down into its separate working parts. In most cases, the bigger the software application and/or its complexity; the bigger the importance to implement such a pattern.
MVC in a simple nutshell:
Controller controls what data is displayed.
View is concerned with how the data is displayed.
Model is the Controller’s source for data. Of course, not necessarily the data eventually displayed.
The Controller is the brains of the operation. It identifies the user’s input, dictates how the model’s data source needs to change (as a result of that input for example), and what data is eventually displayed in the chosen View.
The View and the Model are each tightly coupled to the Controller (i.e. The View knows how to ‘talk to’ the Controller, and the Controller knows how to ‘talk to’ the Model ), ideally however, each has no idea of the other’s existence. On the whole, the View and Model do worked together, but indirectly — through the Controller.
This allows one, for example, to switch out the Model and put in a different one providing a completely different source for the data. Again ideally, the Model would only have to conform to the API requirements so the Controller can ‘talk to’ it correctly. No need or desire to change the Controller since we may return to the original Model, introduce multiple Models, etc. So too with the View. One should be able to switch out the View at will with little consequence.

Dependency Injection
I also wanted an approach that would intrinsically support DI as it too is a recognized technique for reducing coupling. Frankly, you can’t get more intrinsic than passing the three MVC components to each other as parameters:

>>>>>>>>>>>>>>> STOP RIGHT HERE!
The MVC approach has been updated, and is presented in this more recent article: Flutter + MVC at Last!
>>>>>>>>>>>>>> NO NEED TO CONTINUE!
The Controller
Let’s dive right into my current MVC implementation. As you can see in the gist below, I’ve chosen my Controller to be of type _ControllerState which extends State<AppStatefulWidget>. Seems appropriate, as State objects in Flutter are persistent between calls to build(), allowing them to remember information. And as like a Controller should, a State object stored on the widget passed to the runApp() function will then persist for the lifetime of the Flutter application.
Where the magic happens
The magic happens at around line 104. Unlike Flutter’s original approach of calling the build() in an instance of the Class type State<T extends StatefulWidget>. The build() is called where it should be in a MVC design pattern — in the ‘View’ referenced by the variable, _vw.

For example, looking at the ‘Test Drive’ app, introduced to us in Flutter’s Get Started website. The Controller in my ‘MVC version’ looks like this:

This Controller above extends, AppController. There’s an implicit zero-argument constructor inside AppController called which instantiates a Static instance of itself. As it is also a State object, it is this very object that’s returned by StatefulWidget’s createState() function. (see Class, AppStatefulWidget, in the above gist).
The View
Below is a snippet of the ‘Test Drive’ app’s View component. Note, the View can ‘talk to’ the Controller (i.e. It knows the Controller has a function called incrementCounter()). However, it has no idea what’s going on in that function. Nor do we want it to. It doesn’t need to know. Further note how the Controller is referenced — by a little ‘private’ variable called, _con.
Neat and concise.

In Flutter, the user interface (UI) involves widgets. Lots and lots of widgets. It’s the View that’s concern with the UI. It stands to reason the View should have all the widgets — in its build() function. Below is a the full View implementation for the ‘Test Drive’ app. There’s a overridden build() function listed there. One you’ve seen before!
Where the magic happens. Remember?

Note, the Controller Class is passed in as a parameter (i.e. allowing for DI) and assigned to that little instance variable, _con, but not before being passed on to the parent Class, AppView.
Do note further, that the Controller’s ‘inner workings’ is relieved somewhat with ‘${_con.counter}’ . In keeping with OOP encapsulation, some would suggest a function there instead. I would too, but this was just a ‘cut n’ paste’ of the original sample code. Merely placing most of the code into the ‘View’ component.
Regardless, following the MVC design pattern’s intent, any future View’s will have to adhere to the Controller’s API requirements and know to call the Controller’s ‘counter’ property and its incrementCounter() function.
Of course, if you like, instead of ‘hiding’ the Controller reference in that Class by assigning it to a private variable using the underscore, assigning the parameter to a final instance variable making it ‘visible’ (e.g. vw.con) may be more suitable to your particular needs. It’s good to have options.

Let’s continue now and examine the ‘View Class’ that is inherited by this View used by the ‘Test Drive’ app:
You’ll see this ‘View’ Class gives you access to the usual ‘properties’ that you would normally expect when running your many widgets the ‘old way’ — in the build function found in Flutter’s State<T extends StatefulWidget> object:

Further, again as traditionally expected when running your widgets, you can call the function setState() to run, in this case, Controller code.

However, as the comments in the code above implies, you’re violating OOP encapsulation by relieving ‘in the View’ what’s done ‘in the Controller.’ A function call (a function found in the Controller) would be preferred.
But so be it. Developers like options. Right?
The Model
As you see in this ‘Controller’ Class below, the passed Model is not passed on to the parent Class, AppController. Instead, it is assigned to a final instance variable that is ‘visible’ as a Class property. (For example, con.model )

At this point, as of this writing, the AppController Class is only concerned with the integration of Flutter’s StatefulWidget and State<T extends StatefulWidget> Classes. And that’s a good thing, isn’t it? Currently, only it’s subclasses, in this case one named Controller, that are working directly with an object of type Model which, in turn, inherits from the Class, AppModel.

The Model Class is empty. Of course, it is to the programmers to fill it up with the data source of their choosing. And in some cases there’d would no data source, so there’s no need for a Model component at all. Leaving, con.model, in the Controller with a null value. And that’s OK too!

I’ll tell you a little secret.
At this point, as of this writing, the AppModel Class is empty too.
Maybe, in time, I’ll have something put in there for subclasses of this ‘Model type’ to take advantage of. That’s the gift (and curse) of OOP inheritance of course. Heck! In time, maybe a ‘Model type’ will be passed into the AppController Class for some reason or another.
Of course, you can follow the progression of this MVC Flutter Framework in the repo.: github.com/AndriousSolutions/mvc
You’re reading this, and it may be an old article now. I’d like to think many have since contributed to the repo., and the MVC Flutter Framework is much better. Take a look.
Try it out
In your pubspec.yaml, the metadata file located at the root of a Flutter project — used to declare packages and to identify required assets, place a git entry that ‘points’ to the repo. so you can try this all out. Write Classes that extend AppController, AppView, and AppModel,…you’re then on your way.

IThis repo. won’t last forever, and I’ve no intent to publish this MVC Flutter Framework into some Flutter Package. This was just a concept (one that seems to work so far) that I wanted to share. Take the idea, and run with it. Change it. Make it better. Then Share.
Updating and maintaining package releases sounds like too much work. There’d be the feature requests, people asking for this; asking for that, etc.….. I didn’t start my own company so I could work for someone else. :)
Let’s Wrap This Up
Since there’s not much to the ‘MyApp’ class. It’s just calling the super() function for it’s parent Class, App. What say we just wrap up the MVC components in a ‘run’ function? Below is what you’d see then in your main.dart. You can readily see the Dependency Injection of the players involved.
Again, neat and concise.

This ‘run’ function merely calls the runApp() function passing in the MVC Flutter Framework’s own ‘StatefulWidget’ Class, AppStatefulWidget.
Conclusion
Here’s the thing. Whether or not you agree with my particular definition of MVC, I have compartmentalized what I’ve perceived to be the separate areas of responsibly. Now the work and any further development is that much easier. Another developer could come and readily see the building blocks involved and dive into the one they’re now responsible for — all inside Flutter.
Neat.
An MVC Example… Write Your First Flutter App
Testing the MVC Flutter Framework, I “MVC’d” a number of demo and sample apps offered on the Flutter website. The first one I tried it on, was the first one I wrote, the one most of us wrote. It’s found here, Write Your First Flutter App.
A very very simple app that produced random ‘WordPair’s’ and displayed them in an infinite scrolling ListView. Below are the gists that make up my ‘MVC’ version of the app. Note, a Model is utilized in this one.
Note the file, View.dart, has more than one View class in there. That’s fine. With Dependency Injection, I’ve switched out View1 for View2. That took about a second. And, of course, with hot reload…
Here, the Controller is passed an object of type Model. It knows how to ‘talk to’ this Model. In other words, it knows the Model’s property names ‘randomWordPair’ and ‘wordPairs’. However, it further knows how to call them. It calls ‘randomWordPair’ with ‘.asPascalCase’ for example. OPP encapsulation would like to see a function call of course. Something like, String get wordPair => model.randomPair()
…I’ll stop beating my chest on that.
Finally, this Model knows to access the package, english_words.dart, to get its word pairs. The Controller doesn’t know this. The View certainly doesn’t need to know this. The data source could change over time, and if that’s the case, we know where to change it,…and the rest of the app will be none the wiser. Perfect.

Another Example… The Gallery App
The Gallery app is a demo app used to showcase Flutter’s many UI Widgets. It can be found on Flutter’s Technical Overview webpage.
Here, I’m demonstrating the ease in which I ‘migrated’ a traditional Flutter app to the MVC approach. Note, again I’m just ‘cutting n’ pasting’ here. There’s no function calls to the Controller to be found in the View, but maybe that’s not a bad thing. For small projects anyway.
Here’s a snapshot of the directory structure of my version of the Gallery app with the now familiar three MVC files I used to replace the original code.

The Controller for the Gallery App. All the Gallery’s ‘UI’ is placed in the View keeping the original parameters that ‘controls’ how this app works in the Controller. Note the use of the iniState() and the dispose() functions.

The View used in the Gallery App is listed below. The private Controller variable, _con, is highlighted in yellow to emphasize the tight coupling (by design) of the View and the Controller. Now, I didn’t analyze the Gallery App. Possibly there’s some code in the Controller that should rightly be running instead in the View. Hence, for now, the many little yellow boxes.

If that’s the right number of little yellow boxes, even better. Then you’re confident that this file, View.dart, contains all the code responsible for the ‘look and feel’ for the app. The Controller has its role, and the Model (if any) has its role. It’s all good.
Finally, Things Can Get Messy
Of course, you could have all your MVC components ‘talk to’ all the others…if you must. One way right now would be to place them all in static variables. You’d create an ‘MyApp’, for example, where you’d define your static variables. Instantiate your MVC components in that Class.

You then call your ‘MyApp’ Class in main.dart as usual:

Now even your Model has access to the Controller and the View…if you must.

Something I’m not inclined to do. Kinda defeats the whole purpose of this exercise! However, again, programmers like to have options. Admittedly, as of this writing, the Model and the Controller could get away with being a little more tightly coupled. In other words, have the Model contain a reference to the Controller ( e.g. model.con ). This “Kiss” of Flutter Frameworks may reflect that ability in the future.
For now, you’re free to create a method (like the setCon() function below) in your Model Class that you then call in your Controller’s constructor. This then gives your Model access to an instance of your Controller (through a private variable in this case). Possibly there’s some method/properties you need access to in the Controller to help your Model access its data source or what have you. Arguably, this could be deemed acceptable in the MVC design pattern:
