A beginner’s guide to architecting a Flutter app

Suragch
Suragch
Jan 1 · 6 min read

How to use the Provider Architecture package by FilledStacks

Beginners need a simple model to follow

If you are reading this article again for a quick refresher, scroll down to the Summary section at the bottom.

Flutter gives you a lot of freedom to do whatever you want. Sometimes that freedom can be a drawback, though, when you’re starting out. That’s certainly true for state management and app architecture.

I’m a fan of FilledStacks (Dane Mackier) and Reso Coder for their work in educating the Flutter community about app architecture. FilledStacks especially has designed a model of structuring apps which is accessible to beginners. The tutorials tend to be on the long side, though, and the architecture has also evolved over time. That makes it somewhat difficult for a newcomer to understand what is happening.

My goal in this article is to give you a high level understanding of how to architect you app and then some very practical guidance for doing that using the Provider Architecture package by FilledStacks.

Architecture overview

FilledStacks proposes using an MVVM style architecture. The View is usually a widget layout for one screen of your app. It doesn’t contain any logic or state, though. That is contained in the View Model, which doesn’t know any specific details about the View. Most apps need to store and access data and that is handled by Services, which are just Dart classes that abstract away the details so that the View Models don’t need to worry about how it’s done.

You create a new View Model for every screen on your app. The Services are accessible globally, though, so they stay the same. A multi-screen app would be structured something like this:

Practically speaking, the files might be organized something like this:

You are free to use a different organization, though. FilledStacks likes to put the view models in the core folder (at least in the original tutorial). I think I prefer to keep them close to the views that use them, but I may change my mind tomorrow. Read this article for more thoughts on this, but at this point I would just use something like I have above. You can change later when the need arises.

Example

I’ll take you through an easy example now to implement the above architecture. I’ll show you how to create a view and it’s associated view model.

I encourage you to actually work through the example yourself rather than just reading it. This will help you to get a better grasp of the concept.

Start a new project. Call it whatever you want. You’ll get the default counter app, which we’ll modify to start using the MVVM style architecture with the Provider Architecture package.

In pubspec.yaml, add the provider_architecture package:

dependencies:
provider_architecture: ^1.0.5

Note: You don’t actually have to use the Provider Architecture package to implement this architectural pattern. The advantages, though, are that it removes some boilerplate code and also hides away some of the complexities of the Provider package, which it uses internally (hence the name). If you would like to get some background of how all this works under the hood, read the original FilledStacks Provider architecture tutorial and also my previous article Making sense of all those Flutter Providers.

For this example I’m not going to create the full folder structure that I showed above, but you can if you want to.

In the lib/ folder, create a new file called counter_viewmodel.dart. Then paste in the following code:

Note that the class extends ChangeNotifier, which gives you the notifyListeners() method. The view will be a listener, so this method is what the Provider Architecture package will use to rebuild the UI whenever there are changes. ChangeNotifier is part of Flutter foundation, so we don’t actually have any dependencies on the provider_architecture or provider packages here in the view model.

Create a new file in the lib/ folder called counter_screen.dart. This is your UI widget layout for the counter screen.

Paste in the following code:

At the top of the build() method you can see ViewModelProvider. This is what provides the CounterViewModel to the widget tree. Because the state is in the view model, there is no need to use a StatefulWidget. Thus you can see that CounterScreen is a StatelessWidget. It gets the counter value from the view model. When the button is pressed this will call increment() on the view model, which in turn will also trigger a rebuild with the new counter value.

We still have to clean up main.dart. Replace it with the following code:

If you run the app now it should behave exactly like the default counter app.

Pushing the button increments the counter as expected

So far you could have done all that with the plain old Provider package using a ChangeNotifierProvider and a Consumer. A common need, though, is to fetch some initial data from the network or a database. Your view model can expose a method to do these initialization tasks.

Replace counter_viewmodel.dart with the following code:

You can see that now there is a method to fetch some initial data from a web API service. I’m not going to talk about making a service here, so I just included some fake code at the bottom. You can read more about creating an actual service in this article:

The magic of the Provider Architecture package is that ViewModelProvider has an onModelReady callback that allows you to run some initialization code when the view model is ready.

In counter_screen.dart, add the following argument to ViewModelProvider:

onModelReady: (model) => model.loadData(),

Now when you run the app it will update automatically after the two second Future completes.

Summary

Here is a cheat sheet for when you just need a simple reminder for how to get set up in a new project.

Dependency

Add the provider_architecture dependency to pubspect.yaml.

dependencies:
provider_architecture: 1.0.5

View Model

Create a new file called my_screen_viewmodel.dart and add a Dart class that extends ChangeNotifier:

import 'package:flutter/foundation.dart';class MyScreenViewModel extends ChangeNotifier {
int _someValue = 0;
int get someValue => _someValue;
Future loadData() async {
// do initialization...
notifyListeners();
}
void doSomething() {
// do something...
notifyListeners();
}
}

View

Create a new file called my_screen.dart and make your normal widget layout for that screen.

Add a ViewModelProvider to the top of your MyScreen widget tree. The easiest way to do this is to use a shortcut to wrap the top widget with a new widget. Instead of having a child, though, use => to return the top widget from the builder parameter.

import 'package:provider_architecture/provider_architecture.dart';class MyScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ViewModelProvider<MyScreenViewModel>.withConsumer(
viewModel: MyScreenViewModel(),
onModelReady: (model) => model.loadData(),
builder: (context, model, child) => MyTopWidget(

// your widget tree
),
);
}
}

Then within your widget tree you can access the view model like this:

  • model.someValue
  • model.doSomething()

Going on

There are other needs that you will run into as you continue to use the Provider Architecture package. You can read about the other options in the documentation. My explanation above should be enough to get you started, though.

Here are a couple more options that you may want to check out. I’ve found them to be more complex than Provider Architecture, but they still have good things to add.

FilledStacks claims that the Provider Architecture can work for apps of any size. Though I haven’t used it in a large app myself yet, I’m confident that it will give beginning developers a strong foundation for building apps and will carry you well into the intermediate and even advanced levels.

Flutter Community

Articles and Stories from the Flutter Community

Suragch

Written by

Suragch

A Flutter and Dart developer with a background in Android and iOS. Follow me on Twitter @suragch1 for new article notifications.

Flutter Community

Articles and Stories from the Flutter Community

More From Medium

More from Flutter Community

More from Flutter Community

More from Flutter Community

Font Features in Flutter

191

More from Flutter Community

More from Flutter Community

Flutter — Shadows & glows

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade