Making an Android app in itself is not all that hard once you get the basics right. Making a maintainable app is a whole different story. You have to give your code a firm structure, prevent yourself from putting all the code inside an activity or fragment and make many smaller classes which have a single responsibility.
How can you achieve all of this? Architectural patterns! MVC, MVP, MVVM,… While anything is better than the dreaded “spaghetti code”, MVVM is one of the best options for Android development. It’s even fully supported and encouraged by Google with their first-party libraries.
In this tutorial you are going to learn all you need to know to have an idea about what MVVM actually is. As much as I don’t like theory, sometimes it’s important to know it before jumping into actual coding. There is nothing worse than writing code which you don’t understand (been there done that ?).
In another post you will create a real app demonstrating the principles outlined in this theory-centric article. Now without any further ado, let’s learn about MVVM on Android.
Do you prefer video tutorials?
The meaning of Model-View-ViewModel
Separation of concerns is a beautiful thing and every single design pattern tries to do the best that it can to achieve it. In case of MVVM, there are 3 inherent parts which help in accomplishing the separation of concerns: models, views and view models. You can also add a repository which acts as a single source of truth for all the data – more on that later.
In the context of MVVM, View doesn’t mean the base class of all the TextViews and RecyclerViews. Instead it’s a part of your app which handles what the user sees and touches on the screen. In other words, a View does all the things an Activity or a Fragment can do.
Here comes the most important part: Views handle only the immediate interaction with the user. What does this mean? Well, you simply don’t put any business logic like communicating with a database inside your Activities or Fragments. These can only display stuff on the screen (which they get from ViewModels), do Android specific operations and dispatch user interaction events (clicks etc.) to their respective ViewModel.
A ViewModel is like a glue between a View and business logic. It provides data for the view by getting it from the repository.
When you take a look at the diagram above, you might wonder how does a View get all the data which it should display. The arrow is only pointing in one direction, towards the ViewModel. This means that the ViewModel doesn’t have any clue about which Views are using it. While this is amazing for testing and simply less entanglement between classes, the ViewModel still needs to tell the View what data to display.
The trick here is to make the appropriate data in ViewModel observable. By doing this, we get rid of the need to directly update the View from the ViewModel when data changes. A View already has a reference to its ViewModel, so it can simply observe some data which the ViewModel exposes. When the data changes, all of the Views which are observing it will be notified about this change.
This can be done through LiveData which is a handy lifecycle aware library for creating observables. One of its advantages is that it automatically doesn’t notify the observer if its activity or fragment is already destroyed, leaving you free from managing the lifecycle yourself.
Model is where you put all the business specific code. While technically there is an intermediate step between the ViewModel and the Model in the form of a Repository, you can kind of regard everything from Repository downwards as its own group of classes far away from the user interface. These operate on your app’s data and fetch it from the local database or from the network.
Repository has a special role of being a mediator between local storage and the server. This is where you check whether the remote data should be cached locally and so on. Repository is also the single source of truth for ViewModels. In other words, when ViewModel wants some data, it gets it from the Repository. Then it’s up to the repository to decide what to do next. As far as the ViewModel is concerned, the data could be fetched from a toaster or from a supercomputer, it doesn’t care – that’s the business of the repository.
Connectedness of MVVM components
Not only that the View observes data in the ViewModel but also the ViewModel observes data in the Repository which in turn observes data coming from the local database and from the remote data source.
To put this all into perspective, you can think of the connections between models, views, view models, repositories and other classes in the following manner.
When traversing down the hierarchy, the upper class has a direct reference to its child. On the other hand, the child doesn’t have a reference to its parent. Children only expose some data by allowing it to be observed through LiveData or any other library if you so desire.
For a better imagination have a look at the arrow-cluttered diagram below. I wanted to spare you of the non-necessary clutter at the start, that’s why those observable arrows weren’t present in the first diagram showing MVVM.
The last important thing to mention here is that you should always adhere to the reference tree above. For example, don’t make your ViewModel get data from the database directly while bypassing the Repository! Everything has it’s purpose and makes the code modular, easy to maintain and nice to read. You will read your code many more times than you write it so make readability the number one priority. Don’t be lazy to create abstractions, you will thank yourself later.
In this post you learned the concepts behind MVVM architectural pattern. Now that you have the basics, you can start building a real app utilizing this pattern. Subscribe to the news feed and to Reso Coder Youtube channel to be updated when a new tutorial on building an MVVM app comes out.