MVVM architecture pattern in Android Tutorial

Hey Technoz, hope you are doing great. In this tutorial, we are going to talk about MVVM architecture pattern in android app. There are many architecture patterns in android, but MVVM is the most popular and widely used by developers. That’s what we are seeing in this tutorial.

Why use MVVM?

Well, though it is true that most of the developers use MVVM architecture pattern and it is most latest and recommended one, I understand that is not sufficient to start using it. Okay, let me tell few benefits of MVVM pattern to convince you.

  • The MVVM pattern follows separation of concern. That is, each layer is different and it helps us to write separate test cases for each layer.
  • Using ViewModel gives us a protection to keep our data persistent though the activity is recreated, for ex. in case of screen orientation.
  • ViewModel only focuses on business logic in the application and don’t need to worry anything about views. Rather, view is there which keeps observing the changes in data and updates itself automatically.
  • There will one one to many relationship for ViewModel to views. That is, one ViewModel can be used by multiple activities.

Prerequisites:

  • Familiarity with Kotlin and some knowledge about building basic android app.
  • We will be using data binding concept in this tutorial. If you don’t know about data binding, then I would strongly recommend you to go through the below tutorial on Technopoints which focuses on Data Binding.

Data Binding in Android Tutorial

Before going to the implementation, lets see what type of android app we will be building with MVVM Architecture pattern as below.

 

Okay, All set? Nice. Then Lets go to the implementation.

MVVM architecture pattern in Android Implementation

Actually, we are going to build a simple app which deals with student details. It takes student’s roll no., searches the data and shows the relevant results. Thus, create a new Android project with the recommended configuration. Inside this, we will be distinguishing files in separate packages. Create a new package named view and move your MainActivity.kt inside it. This file will be implementing everything inside the UI operations, thus it will go inside view layer.

Create the Layout

At first we will create the UI as shown in above video. Paste the following code inside activity_main.xml.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="student"
            type="com.example.mvvmarchitecturetutorial.model.Student" />
    </data>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".view.MainActivity">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="8dp">

            <TextView
                android:id="@+id/textView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="MVVM Architecture Tutorial"
                android:textSize="30sp"
                app:layout_constraintTop_toTopOf="parent" />

            <EditText
                android:id="@+id/edit_text_roll_no"
                android:layout_width="wrap_content"
                android:layout_height="45dp"
                android:layout_marginTop="16dp"
                android:ems="10"
                android:hint="Enter Roll No."
                android:inputType="phone"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/textView" />

            <Button
                android:id="@+id/search_btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:text="Search"
                app:layout_constraintBottom_toBottomOf="@+id/edit_text_roll_no"
                app:layout_constraintStart_toEndOf="@+id/edit_text_roll_no"
                app:layout_constraintTop_toTopOf="@+id/edit_text_roll_no" />

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:orientation="vertical"
                app:layout_constraintTop_toBottomOf="@+id/search_btn">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="Name"
                    android:textSize="18sp"
                    android:textStyle="bold" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Student Name"
                    android:text="@{student.name}"
                    android:textSize="23sp"
                    tools:text="Ashish Joshi" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Roll No."
                    android:textSize="18sp"
                    android:textStyle="bold" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@{String.valueOf(student.rollno)}"
                    android:textSize="23sp"
                    tools:text="18" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="Standard"
                    android:textSize="18sp"
                    android:textStyle="bold" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@{String.valueOf(student.standard)}"
                    android:textSize="23sp"
                    tools:text="5" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="School"
                    android:textSize="18sp"
                    android:textStyle="bold" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Student School"
                    android:text="@{student.school}"
                    android:textSize="23sp"
                    tools:text="Vivekenand Vidyalaya" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="City"
                    android:textSize="18sp"
                    android:textStyle="bold" />

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="Student City"
                    android:text="@{student.city}"
                    android:textSize="23sp"
                    tools:text="Yavatmal" />
            </LinearLayout>


        </androidx.constraintlayout.widget.ConstraintLayout>
    </ScrollView>
</layout>

I hope you are familiar with data binding. So I won’t go into those details. Let me just explain in brief. The above layout contains:

  • EditText which takes user input (roll no.).
  • Button which helps to search a student record.
  • All other TextViews which are used to display respective student details. They are binded to the different properties in data variable ‘student’ which is of type Student class. We will be creating that class in the next step.

Creating the Model Layer

In this section, we are going to build a model layer in our MVVM architecture tutorial. Create a new package named model  and create a new kotlin data class Student.kt inside it as follows. Remember, whatever the classes we are building in this section, will be created inside the model folder.

package com.example.mvvmarchitecturetutorial.model

data class Student(
    val name : String,
    val rollno : Int,
    val standard : Int,
    val school : String,
    val city : String
)

The model knows from where the data comes from. Thus, it includes the repository. Now we’ll create it. In our project, we have just created a static objects with custom values and referencing those as a repository. The aim of this tutorial is to give an idea about the MVVM architecture. Thus we are making just a dummy repository. If you want, you can easily build your own custom repository using either remote database or local room database. You can refer Room Persistent Data Storage Library Tutorial for that.

Now, create Repository.kt class with the following code.

package com.example.mvvmarchitecturetutorial.model

class Repository {
    fun getStudentData(rollno: Int): Student {
        when (rollno) {
            1 -> {
                return student1
            }
            2 -> {
                return student2
            }
            3 -> {
                return student3
            }
            4 -> {
                return student4
            }
            5 -> {
                return student5
            }
        }
        return student1
    }

    private val student1 = Student(
        "John Doe",
        1,
        5,
        "Preparatory School",
        "New York"
    )

    private val student2 = Student(
        "Will Brown",
        2,
        8,
        "Mentoring the Future",
        "Houston"
    )

    private val student3 = Student(
        "Miles Thomas",
        3,
        6,
        "School of Happy Valley",
        "San Antonio"
    )

    private val student4 = Student(
        "Brian Taylor",
        4,
        7,
        "HighImpact Institute",
        "Philadelphia"
    )

    private val student5 = Student(
        "Dan Evans",
        5,
        5,
        "Wisdom Elementary School",
        "San Diego"
    )
}

in the above class, we have just created 5 instances of Student object with different values and this is our data source. Also, we are creating a function getStudentData() to get the respective student data form these objects using roll number. But, we might have to access the data different times, at different places and it will be tedious to create the instance of repository class every time we need it. Well, single instance can do it with minimum resources. Thus, we are creating single instance of repository class as follows in file RepositoryInstance.ktas follows.

package com.example.mvvmarchitecturetutorial.model

object RepositoryInstance {
    fun getRepoInstance() : Repository {
        val instance : Repository by lazy {
            Repository()
        }
        return instance
    }
}

The above object will create single instance of the repository class and return it. Also, as it is initialized by lazy, the instance will be only created when it is called and the same instance will be served every next time. This completes our Model layer.

Creating the ViewModel

Now its time to create a ViewModel to make MVVM architecture pattern. The ViewModel contains all the business logic we have to incorporate in our app. It is the bridge between view and model layers. Create a separate package viewmodel in project and create a new kotlin class as MainViewModel.kt as follows.

package com.example.mvvmarchitecturetutorial.viewmodel

import androidx.lifecycle.ViewModel
import com.example.mvvmarchitecturetutorial.model.RepositoryInstance
import com.example.mvvmarchitecturetutorial.model.Student

class MainViewModel : ViewModel() {
    var student : Student? = null

    //Creating repository instance
    val repository = RepositoryInstance.getRepoInstance()

    //function to get student data from repository
    fun getStudentData(rollno : Int) {
        student = repository.getStudentData(rollno)
    }
}

In the above class, the MainViewModel is extending the class ViewModel.we are creating nullable instance is Student object and also initializing the repository instance here using the getRepoInstance() method in RepositoryInstance singleton object. This is one of the advantage of using Singleton class that we can directly use the methods inside it. Going further, we create a getStudentData() method which accepts the parameter roll number and calls the method in the repository to get that student details. We are assigning the student details to the nullable instance declared above. This is what ViewModel does in the MVVM architecture in our android app. It doesn’t directly interact with the view but it exposes the result. Thus, view can observe the student object inside MainViewModel.

Creating the View Layer

Finally, we are going to write a logic inside the view layer, which is our MainActivity.kt. Lets create it with the following code in it.

package com.example.mvvmarchitecturetutorial.view

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.mvvmarchitecturetutorial.R
import com.example.mvvmarchitecturetutorial.databinding.ActivityMainBinding
import com.example.mvvmarchitecturetutorial.viewmodel.MainViewModel

class MainActivity : AppCompatActivity() {
    lateinit var binding : ActivityMainBinding
    lateinit var viewModel: MainViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //Initializing viewmodel instance
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
        //initializing data binding instance
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        //if student variable in viewmodel is not null, assign it to binding instance of student
        if (viewModel.student != null){
            binding.student = viewModel.student
        }
        binding.searchBtn.setOnClickListener {
            if (binding.editTextRollNo.text.toString().isBlank()){
                Toast.makeText(this, "Please Enter Roll No.", Toast.LENGTH_SHORT).show()
            } else {
                viewModel.getStudentData(binding.editTextRollNo.text.toString().toInt())
                binding.student = viewModel.student
            }
        }
    }
}

In above code, we are generating an instance of ViewModel class. But, we are not going to simply make a constructor call for MainViewModel. Instead, we are using ViewModelProvider class and calling get method and passing a parameter of our own ViewModel class. Also, we are initializing the binding class instance, as we discussed in Data Binding Tutorial.

In the button click event, we are making a call to the getStudentData() function in MainViewModel so that the student variable in it gets initialized with the respective data and then assigning this value to the binding variable in student. Thus, data binding library will reflect all the changes over the UI instantly.

Before that, we are making a null check for student variable in viewmodel. If it is not null, then we’ll assign that to the student variable of binding class. But, why we are doing this? Well, when the device goes through the orientation change, the activity gets recreated and the local variables gets lost. But, viewmodel doesn’t get destroyed and it retains all the variables in it. so we will reassign value of student variable from the MainViewModel to the student variable in ActivityMainBinding class. In this case, we will not lose our variable values though the activity getting recreate.

Finally, we are done building our android app with MVVM pattern. Lets try running our app and see how it works. If you have some doubts, or getting any issues while implementing the code, let me know in the comments below. I will try my best to resolve them.

Download Source Code

If you don’t want to go through all the code and jump directly to the implementation of MVVM architecture pattern in Android app, feel free to download the source code form the below link.

Download Source Code

Something extra from me… ☺️

Lastly, I would like to offer something extra from my side. Would you like to take it? If yes, then here it is. Technopoints has started its official WhatsApp Group where programming enthusiasts interact with each others, solve doubts, and learn together. There you will be in a group of like-minded people who are eager to learn, share knowledge, ask doubts and solve others doubts too. Additionally, there I share some of the rare programming tips related to Android development, the solution to the challenges I face while making app projects which take my lot of time and I get stuck on it. With those tips, you will avoid common mistakes and conquer the hurdles of your programming journey.

Agree? Great! here is the invite link:

Click here to join the Technopoints WhatsApp Group!

Of course, It is open for programmers all over the Globe. Lets connect, share knowledge and grow together. See you in the next tutorial soon with another new hot topic. Thanks, Good bye! 😄

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.