Skip to main content

MVVM architecture, ViewModel and LiveData (Part 1)

 

MVVM architecture, ViewModel and LiveData (Part 1)


During Google I/O, Google introduced architecture components which includes LiveData and ViewModel which facilitates developing Android app using MVVM pattern. This article discusses how can these components serve an android app that follows MVVM.

Quick Definition of MVVM

If you are familiar with MVVM, you can skip this section completely.

MVVM is one of the architectural patterns which enhances separation of concerns, it allows separating the user interface logic from the business (or the back-end) logic. Its target (with other MVC patterns goal) is to achieve the following principle “Keeping UI code simple and free of app logic in order to make it easier to manage”.

MVVM has mainly the following layers:

  1. Model
    Model represents the data and business logic of the app. One of the recommended implementation strategies of this layer, is to expose its data through observables to be decoupled completely from ViewModel or any other observer/consumer (This will be illustrated in our MVVM sample app below).
  2. ViewModel
    ViewModel interacts with model and also prepares observable(s) that can be observed by a View. ViewModel can optionally provide hooks for the view to pass events to the model.
    One of the important implementation strategies of this layer is to decouple it from the View, i.e, ViewModel should not be aware about the view who is interacting with.
  3. View
    Finally, the view role in this pattern is to observe (or subscribe to) a ViewModel observable to get data in order to update UI elements accordingly.

The following diagram shows MVVM components and basic interactions.

MVVM

LiveData

As said above, LiveData is one of the newly introduced architecture components. LiveData is an observable data holder. This allows the components in your app to be able to observe LiveData objects for changes without creating explicit and rigid dependency paths between them. This decouples completely the LiveData object producer from the LiveData object consumer.

Adding to this, there is also a great benefit in LiveData, LiveData respects the lifecycle state of your app components (activities, fragments, services) and handles object life cycle management which ensures that LiveData objects do not leak.

As per Google Docs, If you are already using a library like Rx or Agera, you can continue using them instead of LiveData. But in this case, it is your responsibility to handle object allocation and de-allocation per Android components life cycle.

Since LiveData respects Android Lifecycle, this means it will not invoke its observer callback unless the LiveData host (activity or fragment) is in an active state (received onStart() but did not receive onStop() for example). Adding to this, LiveData will also automatically remove the observer when the its host receives onDestroy().

LiveData will be illustrated in our MVVM sample app below.

ViewModel

ViewModel is also one of the newly introduced architecture components. Architecture components provide a new class called ViewModel, which is responsible for preparing the data for the UI/View.

ViewModel gives you a good base class for your MVVM ViewModel layer since ViewModel (and its children AndroidViewModel)’s extending classes are automatically having their holding data retained during configuration changes. This means that after configuration changes, this ViewModel holded data is immediately available to the next activity or fragment instance.

The following diagram shows the life cycle of ViewModel component.

The life cycle of ViewModel component

ViewModel will also be illustrated in our MVVM sample app below.


Sample App

Now, let’s come the most interesting part, let’s put all of these things together in a sample app. This MVVM Sample app contains mainly two screens. The first screen which is shown below displays the list of Google GitHub projects with some brief information such as title, programming language, and finally number of watcher.

Project List

Once the app’s end user touch any of the list items, a details screen of the GitHub project appears displaying project description, programming language, number of watcher, open issues, creation and last update date, and finally the clone URL.

Project Details

Sample App Interaction Diagram

The following figure shows the package structure of the Sample App

The following interaction diagram shows a sample interaction diagram of one of the app scenarios to retrieve Google GitHub projects.

As shown in the diagram, every layer observes LiveData from its subsequent layer (Fragment (View) -> ViewModel -> Repository), and finally once project list is retrieved, it is binded with the RecyclerView adapter to display the project list.

Repository modules are responsible should handle data operations. By ensuring this, Repository modules can provide a clean API to the rest of the app and simplify the job of the consumer ViewModel. Repository modules should know where to get the data from and what API calls to make when data is updated if necessary. They can be considered as mediators between different data sources (REST services, Databases, XML files, …etc).

Now, let’s explain these layers from bottom to up, starting with ModelViewModel and finally View for retrieving GitHub projects scenario.

Sample App Model Layer

Let’s start with the business logic layer, we have two model objects

  1. Project, contains the information of GitHub project such as id, name, description, creation date, …etc.
  2. User, contains the user information of the GitHub project owner.

In order to interact with GitHub RESTful API, I used my beloved Retrofit 2 defining the following simple interface under repository package.

In order to facilitate the Job of the ViewModel, a ProjectRepository class is created to interact with GitHub service and to finally provide a LiveData object for ViewModel. It will be also used later to orchestrate service calls. The following code snippet shows getProjectList() API implementation.

ProjectRepository is the data provider for ViewModel, it has getProjectList() which simply wraps the response into LiveData Object.

For the purpose of simplicity of this article, error handling is omitted, and will be illustrated in the next article.

Sample App ViewModel Layer

In order to consume getProjectList() API, a ViewModel class (that calls the Repository API and may do any needed transformation for LiveData) is created. The following code snippet shows ProjectListViewModel class.

As shown above, our ProjectListViewModel class extends AndroidViewModel, and in the constructor, it calls getProjectList(“Google”) to retrieve Google GitHub projects.

In real world cases, a transformation may be needed before passing the result data to the Observing View, in order to make a transformation, you can use Transformation class as shown in the documentation below: https://developer.android.com/topic/libraries/architecture/livedata.html#transformations_of_livedata

Sample App View Layer

Finally, let’s give a quick look into the view layer of this app, we have mainly one Activity called MainActivity which handles the navigation of two fragments that represent the app views:

  1. ProjectListFragment, which displays the list of Google GitHub projects.
  2. ProjectFragment, which displays the selected GitHub project details.

Since Activities and Fragments are considered Life cycle owners, Activities need to extend LifecycleActivity and fragments need to extend LifecycleFragment. However, it is important to keep in mind that both LifecycleActivity and LifecycleFragment classes are temporary implementations until Lifecycles are integrated with support library:
https://developer.android.com/reference/android/arch/lifecycle/LifecycleActivity.html

Now, let’s continue our projects retrieval scenario, looking into ProjectListFragment, the following code snippet shows the most important integration part.

As shown above, ProjectListFragment gets ProjectListViewModel, and then listen to its getProjectListObservable() method in order to get the list of Github projects when ready. Finally, Once the list of projects is retrieved, it is passed to projectAdapter (the RecyclerView adapter) in order to display the list of projects in the RecyclerView component.

This is the explanation of one end-to-end scenario of the project, you can find the complete project available in GitHub here:

https://github.com/hazems/mvvm-sample-app/tree/part1

Important Guiding Principles for MVVM Implementation

Now, it is important to highlight some of the important guiding principles for MVVM implementation:

  1. As shown in the sample, ViewModels do not and must not reference Views directly because if this is done, ViewModels can outlive the View’s lifecycle and memory leakage can happen.
  2. Model and ViewModel are recommended to expose their data using LiveData since LiveData respects the lifecycle state of app components (activities, fragments, services) and handles object life cycle management which ensures that LiveData objects do not leak.

Next Articles

The story does not finish yet, since there are some things which are needed to be handled such as:

  1. Dependency Injection.
  2. Error Handling.
  3. Caching.
  4. Adding more functionality to this demo to see how can Room facilitates SQLite Data operations.
  5. Unit Testing.
  6. Others …

This will be illustrated in the next series of articles of MVVM, Stay tuned.

Finally, I would like to thank 

 for reviewing this article, and giving me a lot of helpful feedback.

Checkout other series articles:
1. MVVM architecture, ViewModel and LiveData — Part 2 (DI): https://proandroiddev.com/mvvm-architecture-viewmodel-and-livedata-part-2-di-1a6b1f96d84b
2. MVVM architecture, ViewModel and LiveData — Part 3 (AndroidX Upgrade): https://proandroiddev.com/mvvm-architecture-viewmodel-and-livedata-part-3-androidx-upgrade-980c4fdbf9d6

If you like this article, I appreciate your support to share this article with others to let the great Android community know.

Comments

All Post

When to Use Waterfall vs. Agile

  We compare the benefits and drawbacks of using two well-known software development methodologies, Waterfall and Agile, and lay out when it might be more suitable to use one over the other – or combine practices of both – for your product initiative. When developing a new software product, your team will need to navigate which development methodology is right for your initiative. In the world of managing  software development  projects, the topic of Agile vs Waterfall is widely debated. Many thought leaders and Agile enthusiasts in the industry have argued Waterfall is dead, however, traditional organizational environments and processes have led to it still being widely used today. A 2017 report from the Project Management Institute shows that  51% of the organizations surveyed use Waterfall either often or always . The reality is, each software development project poses its own unique challenges and requirements. It’s not a matter of deciding which development methodology is “the bes

Flutter form validation: Full guide for you to make Flutter form

  Flutter form validation Getting started with form validation in Flutter The Flutter SDK provides us with an out-of-the-box widget and functionalities to make our lives easier when using form validation. In this article, we’ll cover two approaches to form validation: the form widget and the Provider package. You can find more information on these two approaches in the official Flutter docs. Creating a form in Flutter First, we are going to create a simple login page that has the following fields: Email Name Phone number Password For the validation, we want the users of our app to fill in the correct details in each of these fields. The logic will be defined as such: First, for the name field, we want the user to enter a valid first name and last name, which can be accompanied by initials. For the email field, we want a valid email that contains some characters before the “@” sign, as well as the email domain at the end of the email. For phone number validation, the user is expected to

How to change the language on Android at runtime and don’t go mad

  How to change the language on Android at runtime and don’t go mad TL;DR There is a library called Lingver that implements the presented approach with just a few lined of code.  Check it out! Introduction The topic is old as the hills, but still is being actively discussed among developers due to frequent API and behavior changes. The goal of this post is to gather all tips and address all pitfalls while implementing this functionality. Disclaimer Changing the language on Android at runtime was never officially encouraged or documented. The resource framework automatically selects the resources that best match the device. Such behavior is enough for common applications, so just make sure you have strict reasons to change it before proceeding further. There are a ton of articles and answers on Stack Overflow but they usually lack enough of explanation. As a result, when this functionality gets broken, developers can’t easily fix it due to the messy API and lots of deprecated things. We

7 Key Android Concepts

  Although the Android platform is open and customizable, Android users have become accustomed to constructs developed by Google for Android devices. Although the Android platform is open and customizable, Android users have become accustomed to constructs developed by Google for Android devices. Moreover, the use of these Android concepts is vital in developing an application quickly – custom Android designs can take up to 10 times longer! Android UI Controls Android provides a number of standard UI controls that  enable a rich user experience . Designers and developers should thoroughly understand all of these controls for the following reasons: They are faster to implement. It can take up to ten times longer to develop a custom control than to implement a user interface with standard Android controls. They ensure good performance. Custom controls rarely function as expected in their first implementation. By implementing standard controls, you can eliminate the need to test, revise a

How to them the background of the Android options menu items

  “What we’ve got here is… failure to theme. Some views you just can’t reach. So you get what we had here last project, which is the way Android wants it… well, it gets it. I don’t like it any more than you men.” – Captain, Road Prison 36 Some of you might recognize the previous paragraph as the introduction of Guns ‘N Roses’ Civil War or from the movie Cold Hand Luke starring Paul Newman. This is the feeling I get when I try to create a custom theme for an application on Android. The Android SDK does permit some level of theming, which is not really well documented to start with. Other things are hard-coded, “so you get what we had here last project”. Now, one of the things your application will most likely use is the Options menu, which is the menu you see when you press the hard menu key. It is kind of… orange. In our last project, we had to completely remove the orange in favor of our customer’s color scheme, which is on the blue side. I couldn’t find a way to change the menu item

Clean Code and the Art of Exception Handling

  Clean Code and the Art of Exception Handling Exceptions are as old as programming itself. An unhandled exception may cause unexpected behavior, and results can be spectacular. Over time, these errors have contributed to the impression that exceptions are bad. But exceptions are a fundamental element of modern programming. Rather than fearing exceptions, we should embrace them and learn how to benefit from them. In this article, we will discuss how to manage exceptions elegantly, and use them to write clean code that is more maintainable. Exceptions are as old as programming itself. Back in the days when programming was done in hardware, or via low-level programming languages, exceptions were used to alter the flow of the program, and to avoid hardware failures. Today, Wikipedia  defines exceptions as: anomalous or exceptional conditions requiring special processing – often changing the normal flow of program execution specialized programming language constructs or computer hardware m

Android Jetpack Compose

  Jetpack Compose Tutorial for Android: Getting Started Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs. At Google I/O 2019, Google first announced  Jetpack Compose . Jetpack Compose is Google’s response to the declarative UI framework trend, which the Android team is developing to fundamentally change the way developers create UI, making it easier and faster to write, and more performant to run. It is a part of the Jetpack suite of libraries and as such should provide compatibility throughout platform versions, removing the need to avoid certain features, because you’re targeting lower-end devices or older versions of Android. Although it’s still in an alpha , Compose is already making big waves in the Android community. If you want to stay up-to-date on the latest and greatest technology, read on! In this tutorial, you’

Loops in Dart 💪💪💪😎😎😎

       Loops in Dart   💪💪💪😎😎😎 Dart Loops In Programming, loops are used to repeat a block of code until certain conditions are not completed. For, e.g., if you want to print your name 100 times, then rather than typing print(“your name”); 100 times, you can use a loop. There are different types of loop in Dart. They are: For Loop For Each Loop While Loop Do While Loop Info Note : The primary purpose of all loops is to repeat a block of code. Print Your Name 10 Times Without Using Loop Let’s first print the name 10 times without using a loop. void main() { print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); print( "John Doe" ); } Show Output