MVVM architecture in flutter app example using provider

0
2013

Model-View-ViewModel is referred to as MVVM.

The fundamental concept is to build a view model that feeds information to the view. The view model’s data can be used by the view to fill itself with information. Writing modular code that can be used by multiple views is made possible by the creation of a view-model layer.

Why is MVVM required in flutter?

As far as we are aware, flutter does not support any kind of development architecture. This implies that it must be implemented by developers.

Since MVVM allows you to hold all of your business logic inside the ViewModel class and separate from the UI, it easily demonstrates the need for an architecture to communicate between the UI & business logic.


What is MVVM Flutter?

Model, View, and ViewModel are the three main elements that control MVVM (Model-View-ViewModel).

The key components make it easier to set up a foundation for the MVVM design pattern. Each component has a variety of functions and responsibilities, and a crucial part in the development of the application is played by the key components’ well-founded interactions with one another.

The ViewModel and View interact with each other for data binding in the MVVM architecture. The ViewModel is used to communicate with the model.


Advantages of MVVM architecture

  • MVVM facilitates easier parallel development of a UI and the building blocks that power it
  • MVVM abstracts the View and thus reduces the quantity of business logic (or glue) required in the code behind it. 
  • The ViewModel can be easier to unit test than in the case of event-driven code.

Business logic can be moved from views to viewmodels and models using MVVM. ViewModel serves as a bridge between the view and the model, transferring all user events and returning the outcome.


MVVM (Model-View-ViewModel)

Model

This layer is in charge of transferring data to the ViewModel from the server or a local database.

We define the Network, Local DB, and Repository in this layer so that API, DB, etc. can be communicated with.

ViewModel

Data is transferred between View and Model using ViewModel, which also accepts all user events and asks the Model to respond with data. Once the Model has the data, it goes back to the ViewModel, which then notifies the View of the information.

A single ViewModel can supply data to multiple Views because it can be used by multiple views.

View

The view is the area of the screen where the user interacts with the Widgets displayed there. These user events call for a few actions that direct users to the ViewModel, where the rest of the ViewModel completes the task. ViewModel updates View once it has the necessary data.

We’ll now walk through an example that shows how the MVVM architecture works, using the Provider state mechanism to notify data.

We will now see an example that shows how the MVVM architecture works. To notify data, we will use the Provider, and to make server requests, we will use the HTTP package.

The request is also completed using a repository layer, and the data is then returned to the view through the viewmodel.


MVVM Architecture :

Our MVVM architecture is shown below, and I’m now going to explain the folder structure so that you can understand what should be done as MVVM best practices.

Directory structure

models: For a clean architecture, create inner directories for each API response model class in this directory, which will house all of the model classes for the API response.

view: For the project, this directory will house all the classes related to views, along with subdirectories for each module and widget.

view model: This directory, which optionally includes subdirectories, will house all ViewModel-related classes.


Benefits Of MVVM Architecture For iOS And Android Apps

The primary goal of the mobile app architecture pattern in app development is to support the mobile app development strategies with a broad range of techniques based on vendor- and industry-specific standards that ultimately enhance the creation of the app, whether it be for Android or iOS. Why MVVM is important for your app is a question that most project owners find uncomfortable to answer. In other words, the question makes the claim that “your app can do wonders with this design pattern.”

The Model View ViewModel (MVVM), an acronym for Model View ViewModel, aims to divide the application into three logical components and then handle particular app development aspects. Although the market is flooded with architectural patterns that enhance device capabilities and application performance, the MVVM specifically emphasises the significance of solution architecture in levying a better user interface (UI) experience. The MVVM architecture has many advantages in addition to managing and displaying data objects, some of which are listed below.


Flutter MVVM with provider

Let’s get to the coding part

We must use the ChangeNotifierProvider, a component of the Provider package, to notify the view of the updated MoviesListVM. As shown below, add the dependency for the provider package in the pubspec.yaml file.

Http : ^any
Provider: ^any

Service.dart

This generic class interacts with the ViewModel via a repository class and manages all network requests.

@override
Future getResponse(String url) async {
 dynamic responseJson;
 try {
   final response = await http.get(Uri.parse(mediaBaseUrl + url));
   responseJson = returnResponse(response);
 } on SocketException {
   throw FetchDataException('Oops , No Internet ');
 }
 return responseJson;
}

@visibleForTesting
dynamic returnResponse(http.Response response) {
 switch (response.statusCode) {
   case 200:
     dynamic responseJson = jsonDecode(response.body);
     return responseJson;
   case 400:
     throw BadRequestException(response.body.toString());
   case 401:
   case 403:
     throw UnauthorisedException(response.body.toString());
   case 500:
   default:
     throw FetchDataException(
         'Error occurwhile with server with status code : ${response.statusCode}');
 }
}

Repository

This layer of the repository is in charge of interacting with the network layer and transferring data to the ViewModel class as needed.

BaseService _service = Service();

Future<List<Media>> fetchMediaList(String value) async {
 dynamic response = await _service.getResponse(value);
 final jsonData = response['results'] as List;
 List<Media> mediaList =
     jsonData.map((tagJson) => Media.fromJson(tagJson)).toList();
 return mediaList;
}

ViewModel.dart

ApiResponse _apiResponse = ApiResponse.initial('Empty data');

Media? _media;

ApiResponse get response {
 return _apiResponse;
}

Media? get media {
 return _media;
}

/// Call the media service and gets the data of requested media data of an artist.
Future<void> fetchMediaData(String value) async {
 _apiResponse = ApiResponse.loading('Fetching artist data');
 notifyListeners();
 try {
   List<Media> mediaList = await Repository().fetchMediaList(value);
   _apiResponse = ApiResponse.completed(mediaList);
 } catch (e) {
   _apiResponse = ApiResponse.error(e.toString());
   print(e);
 }
 notifyListeners();
}

void setSelectedMedia(Media? media) {
 _media = media;
 notifyListeners();
}

HomePage.dart

Widget getMediaWidget(BuildContext context, ApiResponse apiResponse) {
 List<Media>? mediaList = apiResponse.data as List<Media>?;
 switch (apiResponse.status) {
   case Status.LOADING:
     return Center(child: CircularProgressIndicator());
   case Status.COMPLETED:
     return Column(
       mainAxisSize: MainAxisSize.min,
       children: [
         Expanded(
           flex: 8,
           child: PlayerListWidget(mediaList!, (Media media) {
             Provider.of<ViewModel>(context, listen: false)
                 .setSelectedMedia(media);
           }),
         ),
         Expanded(
           flex: 2,
           child: Align(
             alignment: Alignment.bottomCenter,
             child: PlayerWidget(
               function: () {
                 setState(() {});
               },
             ),
           ),
         ),
       ],
     );
   case Status.ERROR:
     return Center(
       child: Text('Please try again latter!!!'),
     );
   case Status.INITIAL:
   default:
     return Center(
       child: Text('Search the song by Artist'),
     );
 }
}

@override
Widget build(BuildContext context) {
 final _inputController = TextEditingController();
 ApiResponse apiResponse = Provider.of<ViewModel>(context).response;
 return Scaffold(
   appBar: AppBar(
     title: Text('Media Player'),
   ),
   body: Column(
     children: <Widget>[
       Padding(
         padding: const EdgeInsets.symmetric(vertical: 10.0),
         child: Row(
           children: <Widget>[
             Expanded(
               child: Container(
                 margin: EdgeInsets.symmetric(horizontal: 20.0),
                 decoration: BoxDecoration(
                   color: Theme.of(context).accentColor.withAlpha(50),
                   borderRadius: BorderRadius.circular(30.0),
                 ),
                 child: TextField(
                     style: TextStyle(
                       fontSize: 15.0,
                       color: Colors.grey,
                     ),
                     controller: _inputController,
                     onChanged: (value) {},
                     onSubmitted: (value) {
                       if (value.isNotEmpty) {
                         Provider.of<ViewModel>(context, listen: false)
                             .setSelectedMedia(null);
                         Provider.of<ViewModel>(context, listen: false)
                             .fetchMediaData(value);
                       }
                     },
                     decoration: InputDecoration(
                       border: InputBorder.none,
                       enabledBorder: InputBorder.none,
                       focusedBorder: InputBorder.none,
                       prefixIcon: Icon(
                         Icons.search,
                         color: Colors.grey,
                       ),
                       hintText: 'Enter Artist Name',
                     )),
               ),
             ),
           ],
         ),
       ),
       Expanded(child: getMediaWidget(context, apiResponse)),
     ],
   ),
 );
}

Response.dart

Status status;
T? data;
String? message;

Response.initial(this.message) : status = Status.INITIAL;

Response.loading(this.message) : status = Status.LOADING;

Response.completed(this.data) : status = Status.COMPLETED;

Response.error(this.message) : status = Status.ERROR;

@override
String toString() {
 return "Status : $status \n Message : $message \n Data : $data";
}

This enum manages various UI section states, such as loading, completed, and error.

enum Status { 
INITIAL,
LOADING,
COMPLETED,
ERROR
 }

MVVM and MVC architecture differences

The key distinctions between MVVM and MVC are listed below.

Difference between mvc and mvvm
MVVM (Model View ViewModel)MVC (Model View Controller)
The view serves as the Application’s front door.The Controller is where the Application starts.
View and Viewmodel relationships are one to many.Controller and view relationships are one to many.
Views make use of the View-Model.View Has no connection to the Controller
MVVM is a fairly recent model.Old Model MVC
When we have intricate data bindings, debugging will be challenging.This Model is challenging to read, modify, unit test, and reuse.
MVC Model components may undergo independent testing from users.The code is event-driven and simple for independent unit testing.

Conclusion

I explained the basic structure of the MVVM architecture in a flutter in the article; you can modify this code to suit your needs. This was my brief introduction to Effect On User Interaction, and it works with Flutter.

I hope this blog has given you enough information to try out the MVVM architecture in your flutter projects. We will demonstrate what the Introduction is. Nowadays, MVVM is widely used because it supports an event-driven approach, which is essential because many flutter components operate based on events.

Here you can find the complete repository code , click here

https://github.com/Mitali8620/flutter_MVVM.git

Thank you for taking the time to read this 🙂 Have a Happy day……..