A Framework for Flutter
I stumbled upon this old tweet by Mike Rydstrom the other day. It’s a year-old ranking of the packages used by developers to build their Flutter apps. Nice to see my mvc_pattern is ‘gaining momentum.’ Of course, I can’t see why mine’s not #1 on the list, but that’s neither here nor there. I will have to take a look at these other contributors and see what’s all the hubbub —maybe even write a series of articles on my findings one day. Until then, I’ll continue to contend my framework works great for writing Flutter apps.
Of course, this was all by design. I mean, Google produces a spectacular cross-platform software development kit and framework but doesn’t commit to one approach or another when implementing actual Flutter apps. Instead, they left it to ‘the market’ as it were to determine the best means to implement Flutter. Google did recommend Provider at one point to introduce developers to Flutter, but as you see from that list, there’s a growing number of other ways to work with Flutter. I would think some are primary choices in particular circumstances, but it’s not surprising to me you’ve got a lot to choose from and likely always will.
After all, programming languages have proven to be intrinsically adaptive solutions to almost every Use Case on Earth! I mean, computer software can be found almost everywhere now. It’s become pivotal in almost every aspect of modern life! To meet those diverse and varying problem domains, there can’t be a ‘one-size-fits-all’ approach to developing the software.
As much as it’s desired, you won’t find ‘the one best approach’ in that list above. One could say all are feasible approaches depending on the particulars each can address. With that, I still feel mine’s the best approach. *grin*
This is the first of a series of articles where I will present my case once again and describe what the mvc_pattern package has to offer with an update to its documentation and example app. It’s possible, in time, you’ll find what distinguishes it from the other offerings listed above.
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
What is it?
So, what is this Dart package? It’s a means to organize your code. It offers a consistent approach, a consistent structure, a consistent way to lay out the code that makes up your app. It even suggests separate locations for the code that makes up your app’s business logic, its data source, and its user interface. Thus, it can be called a software design pattern separating what has been seen as typical aspects of all applications: its data, its interface, and its event handling. With that, I would also say it allows for high turnover. With this consistent approach, the next developer to take over a project can ‘hit the ground running’ so as to continue with the app’s development and or maintenance.
This free article, A Design Pattern for Flutter, is a good read as it talks of this ‘organizing of the code’ in further detail. Granted, this article is two years old but the concepts are still relevant. Come back to this article, however, when it gets to the section titled, The App Layer. That’s getting into this custom framework itself, and it has evolved much since then of course.
Show By Example
Let’s introduce this custom framework using a gif file running below. It presents one of two example apps that accompany the mvc_pattern package. It is demonstrating the ready access you have to any particular State object in your app so as to execute its vital setState() function — updating the app’s interface accordingly. Being such a fundamental requirement in Flutter, whole architectures now up on that list have been built just for that very purpose.
Watching the video, you can see there are not one but three counter pages in this example, and the user can easily increment the counter of a previous page from a more advanced page with a tap of a button. Further, you’ll find, unlike page 3, page 2 is able to retain its count even when the user retreats all the way back to page 1 then back to page 2. How is that possible? Finally, back on page 3, you’re able to reset the count back to zero on page 1 — again with a simple tap.
Now all this may sound to be pretty mundane abilities, but it requires your code to safely and reliably gain access to all the State objects involved in your app — all outside their respective build() functions! That’s huge. By design, Flutter does not allow for ready access to State objects as they’re critical to retaining the state of an app. After this series of articles, you’re going to see how it’s done using the mvc_pattern custom framework.
Ready Your Future
By the way, also seen in the video below, I purposely slapped in a delay of 10 seconds to demonstrate the typical requirement of most Flutter apps to open up databases, log into servers, utilize web services, and or initialize third-party plugins at startup. In such cases, your app needs time to get ready before making itself available to the user — a circular progress indicator is displayed at startup to represent that time being taken.
This is such a common requirement, this custom framework supplies the ready means to run such code at startup with a FutureBuilder widget being the most common approach to do so. The initAsync() function is utilized, but it’s just one of a dozen functions and features offered by the framework to make full-fledged production-ready Flutter apps.
Why is it?
So like some of those architectures listed above, I wrote this framework because I wanted ready access to any particular State object. I could then call its setState() function from outside of its build() function any time I wanted. However, that wasn’t the very first reason I built this framework. Back in March of 2018, when I was first learning Flutter, I was getting a little frustrated with the StatefulWidget. Being such an important player in the Flutter framework, it took time to figure out how I was going to work it. As you know, a State class accompanies a StatefuleWidget and contains the ever-important build() function. It’s that function that essentially returns the Flutter app’s interface, and so I felt when I implement a State class, it should only contain code regarding the app’s interface.
As is advocated by many software design patterns, I regularly choose to separate an app’s code into those three areas of responsibility I’ve mentioned: its interface, its data source, and its event handling. This approach has proven time and time again to alleviate the complexities that often arise in software development. I quickly discovered when I was first learning Flutter that keeping all the code that makes up an app in a State class makes development unnecessarily tedious. There‘s a lot of scrolling up and down the soon-to-be immense streams of code in that one Dart file. Not good.
It was during that time, three years ago, I was wondering where’s the app’s event handling, its business rules, the very logic of the app should be found. The StatefulWidget class was out of the question. By design, a StatefulWidget is created, destroyed, and recreated again and again during the lifetime of a typical Flutter app. There’s just a warning, but it should be downright prohibited for a developer to write any extraneous code in a StatefulWidget. All that should be in a StatefulWidget is its createState() function creating its State object. If there is to be additional code, it’s crucial that it’s immutable code.
When you first started learning Flutter, I’ve no doubt you’ve encountered that warning essentially saying: “This class is marked as ‘@immutable’, but one or more of its instance fields aren’t final.” Below is such example where the keyword, final, was removed from the instance field, title, in the StatefulWidget, MyHomePage.
Do yourself a favor, and don’t ignore such warnings. Such ‘mutable’ properties in a StatefulWidgat are just taking up memory, using up CPU cycles, and only impeding performance. No, I finally concluded, this called for a separate Dart library file. A file to contain the ‘Controller.’
This concept is not unknown to Flutter. I suspect you’ve already encountered a number of Controllers working with the Flutter framework. They’re literally being passed to named parameters called ‘controller.’ One of the more prominent instances is when you use the TextField widget. It has a controller to supply the initial field value for example. It handles all the events involved when editing the data in that field.
Another common place you would encounter a Controller is when using the SingleChildScrollView widget. It is supplied a controller to, again, address the series of events that occur during its typical operations. In this case, when scrolling its displayed data. As it happens, it has proven to be very advantageous to introduce a Controller to Flutter’s StatefulWidgets in the same manner and purpose. It makes for building Flutter apps that much easier frankly. However, there was yet another reason for this framework.
The Cycle Of Life
Another reason for it was due to the fact I was coming from the Android world and had grown accustomed to working with the ‘life-cycle’ events that commonly occur in Android apps. I soon discovered implementing such a means in Flutter apps involved the WidgetObserver class and the command:
WidgetsBinding.instance!.addObserver(this). With this, you would then have the didChangeAppLifecycleState() function available to you. It allows you to readily work with your Flutter app’s own life cycle. The custom framework sets this up for you and makes working with the app’s life cycle very intuitive.
In fact, you’re now privy to a number of system events potentially affecting your app. All readily accessible by these new ‘State Controllers.’ They are in the form of functions, and all are listed below. I would think you’ll readily recognize them or at least appreciate their importance.
State Of Access
The remaining functions found in these Controllers pertain to that ready access to the State object so coveted by those other contributors listed above. Indeed, it is a powerful capability.
Finally, there was the need for error handling. We developers are guilty of two things. We don’t do documentation, and we don’t do error handling. We spend so much time getting the app to work right, we tend not to anticipate if and when things go wrong. You have to face the fact errors can happen — even in your precious code. This is another reason why I wrote this framework — to easily implement error handling. As for documentation…well, who wants to do documentation?? That’s for another article.
One of my more popular articles, Error Handling in Flutter, dives deeper into error handling. The link is not behind a paywall and so is free for your perusal. Being such an important yet often overlooked aspect of development, it’s one I addressed early on when learning this marvelous cross-platform solution we call Flutter.
As I got to know how Flutter works. I came to appreciate the fact that each implemented StatefulWidget in my apps was a little micro-app in itself. Following the modular approach to programming, the State object within each StatefulWidget was responsible for one particular task in most cases. These StatefulWidgets were self-contained — relying only on their own little bit of code (mostly found in their ‘new’ State Controller). However, if that one StatefulWidget blew up, there tended to be a cascading effect and the whole app would crash. You’re then greeted with that ‘Red Screen of Death.’
No, the other reason for the custom framework, was because I felt each StatefulWidget should be able to handle their own errors. You should have the option to implement an Error Handler in any and all of your app’s State objects, and so I provided that option when using this custom framework.
The first screenshot below of the package’s second example app. Note, to implement this custom framework, all it takes really is to override the class StateMVC. The State object can then take in a Controller when calling its constructor. It is at this point, that the State object, _MyHomePageState, could implement its own error handling. The second screenshot below is that of the StateMVC class itself and its last defined function, onError(). If the State object, _MyHomePageState, does not override its onError(), any errors during its run will produce the good ol’ ‘Red Screen of you-know-what.’ Otherwise, as mentioned in the article referenced above, you could implement the onError() instead and have options. Gotta love options.
Conceivably, you could assign each State object its own error handler. Possibly you want to catch specific errors in a specific fashion depending on certain circumstances in different parts of your app. Regardless, you can then safely save data when necessary, close low-level files, etc. Anyway, it’s something I felt should be an option, so I wrote this framework.
Keep It Simple & Keep It Flutter
Well, this is a good start to this series. Additional stories of about this length will continue on from here examining those two example apps in more detail — giving you a full appreciation of what the mvc_pattern can do for you. If you want to use it, I feel you’ll find it very helpful. Mind you, I don’t use the mvc_pattern package anymore— not directly anyway. Eventually, I developed a more comprehensive framework package called, mvc_application, which does everything I need to make a truly full-fledged production-ready cross-platform application. It accelerates the development of my Flutter apps using the package, mvc_pattern, at its core.
Also, on December 31, 2021, I release a ‘Web’ version called, mvc_web. You guessed it, it’s a framework to build Flutter Web apps. It works with mvc_application which, in turn, works with mvc_pattern. Of course, it all works with Flutter and not ‘on top of’ Flutter with its own way of doing things — like I hear some of those contributions do listed above.
Finally, I was joking when I boasted mine was the best one. That’s not true. No, it’s the other package I wrote called, state_set. That’s the best one…but that’s neither here nor there.
Important Update for 2023!
The MVC Flutter Framework has since been renamed Fluttery Framework. It’s the same framework…only better. The concepts you’ve read above still apply — only the ‘MVC’ label has been removed. The framework has merely been renamed. I encourage you to continue reading the series above. Simply use this newly named framework instead.
Below is another article describing how the Fluttery Framework (once called mvc_application) is applied to a real-world educational app highlighting some of the wonders in the World. Further below is the GitHub repository for the Fluttery Framework.