•  

    Model–View–ViewModel (MVVM) is a very established architectural pattern when it’s come to software development. What is so special about MVVM?

    MVVM is useful to move business logic from view to ViewModel and Model. ViewModel is the mediator between View and Model which carry all user events and return back the result.

     

    There are three key things that flow out of applying MVVM

    • Maintainability:- The presentation layer and the logic are loosely coupled, due to this code is easily maintainable and reusable. As the code base will increase over the course of time, this will help you to distinguish between them.
    • Testability:- The ViewModel is easier to unit test than code-behind or event-driven code. Thanks to separation logic MVVM have 😀
    • Extensibility:- This architecture gives you assurance which enables code to get extensible over the period of time. but keep in mind it’s also over job to keep component reusable.

    Model

    The model represents a single source of truth that carries the real-time fetch data or database-related queries.

    This layer can contain business logic, code validation, etc. This layer interacts with ViewModel for local data or for real-time. Data are given in response to ViewModel.

    ViewModel

    ViewModel is the mediator between View and Model, which accept all the user events and request that to Model for data. Once the Model has data then it returns to ViewModel and then ViewModel notify that data to View.

    ViewModel can be used by multiple views, which means a single ViewModel can provide data to more than one View.

    View

    The view is where the user is interacting with Widgets that are shown on the screen. These user events request some actions which navigate to ViewModel, and the rest of ViewModel does the job. Once ViewModel has the required data then it updates View.

    Now, we will go through the example which will demonstrate MVVM architecture, for notifying data we will use the Provider state mechanism.


    Add Dependencies

    provider: ^6.0.1
    http: ^0.13.3

     

     

    MediaService.dart

    import 'dart:convert';
    import 'dart:io';
    import 'package:meta/meta.dart';
    
    import 'package:http/http.dart' as http;
    import 'package:mvvm_flutter_app/model/apis/app_exception.dart';
    
    class MediaService {
      final String _baseUrl = "https://itunes.apple.com/search?term=";
    
      Future<dynamic> get(String url) async {
        dynamic responseJson;
        try {
          final response = await http.get(_baseUrl + url);
          responseJson = returnResponse(response);
        } on SocketException {
          throw FetchDataException('No Internet Connection');
        }
        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 occured while communication with server' +
                    ' with status code : ${response.statusCode}');
        }
      }
    }

    MediaRepository.dart

    import 'package:mvvm_flutter_app/model/media.dart';
    import 'package:mvvm_flutter_app/model/services/media_service.dart';
    
    class MediaRepository {
      MediaService _mediaService = MediaService();
    
      Future<List<Media>> fetchMediaList(String value) async {
        dynamic response = await _mediaService.get(value);
        final jsonData = response['results'] as List;
        List<Media> mediaList =
            jsonData.map((tagJson) => Media.fromJson(tagJson)).toList();
        return mediaList;
      }
    }

    MediaViewModel.dart

    import 'package:flutter/cupertino.dart';
    import 'package:mvvm_flutter_app/model/apis/api_response.dart';
    import 'package:mvvm_flutter_app/model/media.dart';
    import 'package:mvvm_flutter_app/model/media_repository.dart';
    
    class MediaViewModel with ChangeNotifier {
      ApiResponse _apiResponse = ApiResponse.loading('Fetching artist 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 {
        try {
          List<Media> mediaList = await MediaRepository().fetchMediaList(value);
          _apiResponse = ApiResponse.completed(mediaList);
        } catch (e) {
          _apiResponse = ApiResponse.error(e.toString());
          print(e);
        }
        notifyListeners();
      }
    
      void setSelectedMedia(Media media) {
        _media = media;
        notifyListeners();
      }
    }

    HomScreen.dart

    import 'package:flutter/material.dart';
    import 'package:mvvm_flutter_app/model/apis/api_response.dart';
    import 'package:mvvm_flutter_app/model/media.dart';
    import 'package:mvvm_flutter_app/view/widgets/player_list_widget.dart';
    import 'package:mvvm_flutter_app/view/widgets/player_widget.dart';
    import 'package:mvvm_flutter_app/view_model/media_view_model.dart';
    
    import 'package:provider/provider.dart';
    
    class HomeScreen extends StatefulWidget {
      @override
      _HomeScreenState createState() => _HomeScreenState();
    }
    
    class _HomeScreenState extends State<HomeScreen> {
      @override
      void initState() {
        // TODO: implement initState
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        final _inputController = TextEditingController();
        ApiResponse apiResponse = Provider.of<MediaViewModel>(context).response;
        List<Media> mediaList = apiResponse.data as List<Media>;
        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<MediaViewModel>(context)
                                      .setSelectedMedia(null);
                                  Provider.of<MediaViewModel>(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',
                              )),
                        ),
                      ),
                    [,
                  ),
                ),
                mediaList != null && mediaList.length > 0
                    ? Expanded(
                        child: PlayerListWidget(mediaList, (Media media) {
                        Provider.of<MediaViewModel>(context)
                            .setSelectedMedia(media);
                      }))
                    : Expanded(
                        child: Center(
                          child: Text('Search the song by Artist'),
                        ),
                      ),
                if (Provider.of<MediaViewModel>(context).media != null)
                  Align(
                      alignment: Alignment.bottomCenter,
                      child: PlayerWidget(
                        function: () {
                          setState(() {});
                        },
                      )),
              ],
            ));
      }
    }
0 Years in
Operation
0 Loyal
Clients
0 Successful
Projects

Words from our clients

 

Tell Us About Your Project

We’ve done lot’s of work, Let’s Check some from here