Tutorial

Android MVVM Design Pattern

Published on August 3, 2022
author

Anupam Chugh

Android MVVM Design Pattern

In this tutorial, we’ll be discussing and implementing the Android MVVM Architectural Pattern in our Android Application. We’ve previously discussed the Android MVP Pattern.

Why do we need these patterns? Adding everything in a Single Activity or Fragment would lead to problems in testing and refactoring the code. Hence, the use of separation of code and clean architecture is recommended.

Android MVVM

MVVM stands for Model, View, ViewModel.

  • Model: This holds the data of the application. It cannot directly talk to the View. Generally, it’s recommended to expose the data to the ViewModel through Observables.
  • View: It represents the UI of the application devoid of any Application Logic. It observes the ViewModel.
  • ViewModel: It acts as a link between the Model and the View. It’s responsible for transforming the data from the Model. It provides data streams to the View. It also uses hooks or callbacks to update the View. It’ll ask for the data from the Model.

The following flow illustrates the core MVVM Pattern. android mvvm pattern How does this differ from MVP?

  • ViewModel replaces the Presenter in the Middle Layer.
  • The Presenter holds references to the View. The ViewModel doesn’t.
  • The Presenter updates the View using the classical way (triggering methods).
  • The ViewModel sends data streams.
  • The Presenter and View are in a 1 to 1 relationship.
  • The View and the ViewModel are in a 1 to many relationship.
  • The ViewModel does not know that the View is listening to it.

There are two ways to implement MVVM in Android:

  • Data Binding
  • RXJava

In this tutorial, we’ll be using Data Binding only. Data Binding Library was introduced by Google in order to bind data directly in the xml layout. For more info on Data Binding, refer this tutorial. We’ll be creating a simple Login Page Example Application that asks for user inputs. We’ll see how the ViewModel notifies the View when to show a Toast Message without keeping a reference of the View.

How is it possible to notify some class without having a reference of it? It can be done in three different ways:

  • Using Two Way Data Binding
  • Using Live Data
  • Using RxJava

Two Way Data Binding

Two-way Data Binding is a technique of binding your objects to your XML layouts such that the Object and the layout can both send data to each other. In our case, the ViewModel can send data to the layout and also observe changes. For this, we need a BindingAdapter and custom attribute defined in the XML. The Binding Adapter would listen to changes in the attribute property. We’ll learn more about Two-way Data Binding through our example below.

Android MVVM Example Project Structure

Adding the Data Binding Library

Add the following code to your app’s build.gradle file:

android {

    dataBinding {
        enabled = true
    }
}

This enables Data Binding in your Application.

Adding the Dependencies

Add the following dependencies in your build.gradle file :

implementation 'android.arch.lifecycle:extensions:1.1.0'

Model

The Model would hold the user’s email and password. The following User.java class does it:

package com.journaldev.androidmvvmbasics.model;


public class User {
    private String email;
    private String password;

    public User(String email, String password) {
        this.email = email;
        this.password = password;
    }

    public void setEmail(String email) {
        this.email = email;
    }


    public String getEmail() {
        return email;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    public String getPassword() {
        return password;
    }


}

Two-way Data Binding allows us to bind objects in the XML layouts such that the object can send data to the layout, and vice versa. The Syntax for two way data binding is @={variable}

Layout

The code for the activity_main.xml is given below:

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

    <data>

        <variable
            name="viewModel"
            type="com.journaldev.androidmvvmbasics.viewmodels.LoginViewModel" />
    </data>


    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_margin="8dp"
            android:orientation="vertical">

            <EditText
                android:id="@+id/inEmail"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Email"
                android:inputType="textEmailAddress"
                android:padding="8dp"
                android:text="@={viewModel.userEmail}" />


            <EditText
                android:id="@+id/inPassword"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Password"
                android:inputType="textPassword"
                android:padding="8dp"
                android:text="@={viewModel.userPassword}" />


            <Button
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="8dp"
                android:onClick="@{()-> viewModel.onLoginClicked()}"
                android:text="LOGIN"
                bind:toastMessage="@{viewModel.toastMessage}" />


        </LinearLayout>

    </ScrollView>

</layout>

Data Binding requires us to set the layout tag at the top. Here our ViewModel binds the data to the View. ()-> viewModel.onLoginClicked() invokes the Button click listener lambda defined in our ViewModel. The EditText updates the values in the Model (via View Model). bind:toastMessage="@{viewModel.toastMessage}" is a custom attribute we’ve created for two-way data binding. Based on changes in the toastMessage in the ViewModel the BindingAdapter would get triggered in the View.

ViewModel

The code for the LoginViewModel.java is given below:

package com.journaldev.androidmvvmbasics.viewmodels;

import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.text.TextUtils;
import android.util.Patterns;

import com.android.databinding.library.baseAdapters.BR;
import com.journaldev.androidmvvmbasics.model.User;

public class LoginViewModel extends BaseObservable {
    private User user;


    private String successMessage = "Login was successful";
    private String errorMessage = "Email or Password not valid";

    @Bindable
    private String toastMessage = null;


    public String getToastMessage() {
        return toastMessage;
    }


    private void setToastMessage(String toastMessage) {

        this.toastMessage = toastMessage;
        notifyPropertyChanged(BR.toastMessage);
    }


    public void setUserEmail(String email) {
        user.setEmail(email);
        notifyPropertyChanged(BR.userEmail);
    }

    @Bindable
    public String getUserEmail() {
        return user.getEmail();
    }

    @Bindable
    public String getUserPassword() {
        return user.getPassword();
    }

    public void setUserPassword(String password) {
        user.setPassword(password);
        notifyPropertyChanged(BR.userPassword);
    }

    public LoginViewModel() {
        user = new User("","");
    }

    public void onLoginClicked() {
        if (isInputDataValid())
            setToastMessage(successMessage);
        else
            setToastMessage(errorMessage);
    }

    public boolean isInputDataValid() {
        return !TextUtils.isEmpty(getUserEmail()) && Patterns.EMAIL_ADDRESS.matcher(getUserEmail()).matches() && getUserPassword().length() > 5;
    }
}

The methods were called in the layout are implemented in the above code with the same signature. If the XML counterpart of the method doesn’t exist, we need to change the attribute to app:. The above class can also extend ViewModel. But we need BaseObservable since it converts the data into streams and notifies when the toastMessage property is changed. We need to define the getter and setter for the toastMessage custom attribute defined in the XML. Inside the setter, we notify the observer (which will be the View in our application) that the data has changed. The View(Our activity) can define the appropriate action.

BR class is auto-generated from data binding when you rebuild the project

The code for the MainActivity.java class is given below:

package com.journaldev.androidmvvmbasics.views;


import android.databinding.BindingAdapter;
import android.databinding.DataBindingUtil;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;


import com.journaldev.androidmvvmbasics.R;
import com.journaldev.androidmvvmbasics.databinding.ActivityMainBinding;
import com.journaldev.androidmvvmbasics.viewmodels.LoginViewModel;


public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityMainBinding activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        activityMainBinding.setViewModel(new LoginViewModel());
        activityMainBinding.executePendingBindings();

    }

    @BindingAdapter({"toastMessage"})
    public static void runMe(View view, String message) {
        if (message != null)
            Toast.makeText(view.getContext(), message, Toast.LENGTH_SHORT).show();
    }
}

Thanks to DataBinding, the ActivityMainBinding class is auto-generated from the layout. The @BindingAdapter method gets triggered whenever toastMessage attribute defined on the Button is changed. It must use the same attribute as defined in the XML and in the ViewModel. So in the above application, the ViewModel updates the Model by listening to the changes in the View. Also, the Model can update the view via the ViewModel using the notifyPropertyChanged The output of the above application in action is given below: android mvvm data binding demo This brings an end to this tutorial on Android MVVM Using DataBinding. You can download the project from the link given below.

AndroidMVVMBasics

Github Project Link

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the author(s)

Category:
Tutorial

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
May 28, 2018

Great tutorial. But i’m facing a little problem. When I rotate the phone, the data remains there… when I “rerotate” de phone, the data remains there, but the cursor comes back to initial point… Do you have some thoughts about it?

- Victor

JournalDev
DigitalOcean Employee
DigitalOcean Employee badge
August 3, 2018

Hi Victor, Add the following line in your activity onCreate below setViewModel() activityMainBinding.executePendingBindings();

- Anupam Chugh

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    July 10, 2018

    This is not pure MVVM pattern, It is mixture of MVVM and MVP. In MVVM ViewModel doesn’t know about View, but here ViewModel has reference of View(Activity) through LoginResultCallback .

    - Shubham

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    August 3, 2018

    Exactly, this is MVP with some kind of ViewModel smell and data binding (which doesn’t make it MVVM). This MVVM is not correctly implemented. Learn what LiveData is and how to implement it or use RxJava.

    - Glenn S

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    August 3, 2018

    Hi Glenn, MVVM can be implemented with DataBinding or RxJava. This tutorial demonstrates MVVM with Data Binding only. We are not obliged to use LiveData with MVVM always. To prevent this tutorial from becoming too long we have omitted LiveData. Stay tuned for the tutorials in which we’ll use LiveData and also the one with RxJava and MVVM. Thanks

    - Anupam Chugh

    JournalDev
    DigitalOcean Employee
    DigitalOcean Employee badge
    August 4, 2020

    where is the tutorial that contains LiveData

    - Ahmed

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      August 4, 2018

      Hi Shubham, MVVM states that the ViewModel must not have a direct reference of the View For that we can use interface callbacks as I did earlier OR Two-way data binding. Check the updated post! Thanks

      - Anupam Chugh

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      September 16, 2018

      Hi Anupam, I did all of the steps in your article. and don’t see that the ViewModel refers to Activity. I think the issue that Shubham mentioned had been resolved by your, right? Thanks for your post.

      - Rain Liu

      JournalDev
      DigitalOcean Employee
      DigitalOcean Employee badge
      September 16, 2018

      Yes indeed. Glad it helped you.

      - Anupam Chugh

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        August 11, 2018

        Hello, Is there a way i can subscribe to you, so that I would be notified whenever a new article related to Android/Java is posted. Your articles are great. Thanks Aakash

        - Aakash Jain

        JournalDev
        DigitalOcean Employee
        DigitalOcean Employee badge
        August 12, 2018

        Hi Aakash, You can always enable push notifications in your web browser. Or you can download our Android Application from Play Store. We send notifications whenever any new article is published.

        - Anupam Chugh

          JournalDev
          DigitalOcean Employee
          DigitalOcean Employee badge
          August 24, 2018

          hi,i do this step by step but it showed me a “duplicate class found in activity_main.xml” error! please help

          - امیر

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            August 27, 2018

            Hi, If I don’t use Databinding/Livedata, then will my app fall in MVVM pattern?

            - Tushar

            JournalDev
            DigitalOcean Employee
            DigitalOcean Employee badge
            August 29, 2018

            You can use RxJava.

            - Anupam Chugh

              JournalDev
              DigitalOcean Employee
              DigitalOcean Employee badge
              September 26, 2018

              Found data binding errors. ****/ data binding error ****msg:Cannot find the setter for attribute ‘bind:toastMessage’ with parameter type java.lang.String on android.widget.Button

              - Luciano Moura

                JournalDev
                DigitalOcean Employee
                DigitalOcean Employee badge
                December 26, 2018

                Brother can you give me same example of mvvb and mvp to understand the patterns better ?

                - Md. Rafsan Biswas

                  JournalDev
                  DigitalOcean Employee
                  DigitalOcean Employee badge
                  January 11, 2019

                  Hi Anupam, From past few days i have been searching for mvvm in android, then i have found yours code simple and understandable, but as the comments section says this is not pure mvvm, So, please can u provide the pure mvvm understandable example for simple login page. Please help ASAP, I am in extreme need of it. Thank you in advance.

                  - Rajesh

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    January 29, 2019

                    ViewModel: It acts as a link between the Model and the ViewModel. I think it should be “It acts as a link between the Model and the View”

                    - Pratik Butani

                    JournalDev
                    DigitalOcean Employee
                    DigitalOcean Employee badge
                    January 29, 2019

                    Thanks for noticing the typo, I have fixed it.

                    - Pankaj

                      JournalDev
                      DigitalOcean Employee
                      DigitalOcean Employee badge
                      February 5, 2019

                      Very neat and simple to understand this tutorial. I though MVVM is very hard to learn, but with your support and tutorial it makes me learner. Thanks lot man!! But i am obstruction of below error… Please help to find this error Found data binding errors. ****/ data binding error ****msg:cannot find method afterEmailTextChanged(android.text.Editable) in class com.eyeraise.kot.model.login.LoginModel file:/Users/bala/Documents/Muthu/Source/eyeraise/kot/app/src/main/res/layout/activity_login.xml loc:27:64 - 27:104 ****\ data binding error ****

                      - Muthukumar Subramaniam

                      JournalDev
                      DigitalOcean Employee
                      DigitalOcean Employee badge
                      February 5, 2019

                      Found my issue in layout I wrongly mentioned type model

                      - Muthukumar Subramaniam

                        JournalDev
                        DigitalOcean Employee
                        DigitalOcean Employee badge
                        February 7, 2019

                        Thanks. Great that you figured out the issue yourself.

                        - Anupam Chugh

                          JournalDev
                          DigitalOcean Employee
                          DigitalOcean Employee badge
                          February 26, 2019

                          please let me know how i can set two or multiple different validation message for email and password

                          - Gagan

                            JournalDev
                            DigitalOcean Employee
                            DigitalOcean Employee badge
                            March 1, 2019

                            Your tutorial is good but you have incorrect information you said you using Two way binding but in reality you still using one way binding with illusion of two way binding. in two way binding we don’t need listeners to listen for changes, that’s the whole point of the Two way binding maybe you set notifyPropertyChanged and Bindable but both are useless remove them and this code still work because it’s not two way binding in two way binding we directly observe for changes using notifyPropertyChanged and Bindable and the change appear in our setter method without any listener and most impotent thing we have to use @={ } Notation to define TWO WAY binding not @{ } that you used. here just starting few lines will tell you…checkout this and update post. https://developer.android.com/topic/libraries/data-binding/two-way

                            - Ashwini Violet

                            JournalDev
                            DigitalOcean Employee
                            DigitalOcean Employee badge
                            March 1, 2019

                            Thanks, Ashwini for noticing that. I’ve updated the tutorial.

                            - Anupam Chugh

                              JournalDev
                              DigitalOcean Employee
                              DigitalOcean Employee badge
                              March 22, 2019

                              If i want to start a new activity on click of Login button then how to implement setOnClickListener() inside MainActivity ??

                              - Gourav

                                JournalDev
                                DigitalOcean Employee
                                DigitalOcean Employee badge
                                March 31, 2019

                                why we should use bindingadapter for toast message? why do email and password not use binding adapter?

                                - Angga

                                JournalDev
                                DigitalOcean Employee
                                DigitalOcean Employee badge
                                April 22, 2019

                                Because we are just observing the changes in email and password, Both email and password is bound to the XML via ViewModel so that when there values are updated our ViewModel is notified and we do not have to make a call to getText again and again, But we are not doing any UI update or any complex transactions. Here we are updating UI(showing and updating toast message string based on the validity of login credentials) hence we have bound it with a adapter so as soon as the toast message is update, the UI will be updated as well.

                                - Aastha

                                  JournalDev
                                  DigitalOcean Employee
                                  DigitalOcean Employee badge
                                  June 26, 2019

                                  Thank you for great explanation. Only one question- How to move to other activity in case of login success? Where and how the correct point to do that?

                                  - Matan Marciano

                                    JournalDev
                                    DigitalOcean Employee
                                    DigitalOcean Employee badge
                                    July 17, 2019

                                    in your entire code you missed one annotation , due to which BR will never generate. The annotation would be @Bindable above the two getters inside the model class.

                                    - Rahul Ghosh

                                      JournalDev
                                      DigitalOcean Employee
                                      DigitalOcean Employee badge
                                      July 18, 2019

                                      Hi Thanks for you tutorial, How to get the email id and password in activity while pressing the button, because in your case you just showing the toast message like success or failure in view model, but there is no function to show the input details in activity.

                                      - Ananth

                                        JournalDev
                                        DigitalOcean Employee
                                        DigitalOcean Employee badge
                                        September 1, 2019

                                        Does BR.userEmail inside setUserEmail(String email) method generated for you? Becuse there is no such property called userEmail defined inside LoginViewModel. Can you please explain?

                                        - Satyasarathi

                                        JournalDev
                                        DigitalOcean Employee
                                        DigitalOcean Employee badge
                                        March 27, 2020

                                        Hellow, u can rebuild your program.So BR will auto-generated

                                        - Dio

                                          JournalDev
                                          DigitalOcean Employee
                                          DigitalOcean Employee badge
                                          April 24, 2020

                                          hello, after adding these lines, the error is not showing for me. @Bindable private String userEmail = null; @Bindable private String userPassword = null;

                                          - sriraksha

                                            JournalDev
                                            DigitalOcean Employee
                                            DigitalOcean Employee badge
                                            September 6, 2019

                                            I have implemented the same code using Kotlin. I am not understanding why the toast message is shown initially while opening the app. I want to show the toast only on the click of the login button. How to achieve this?

                                            - Keerthi Prasad B V

                                            JournalDev
                                            DigitalOcean Employee
                                            DigitalOcean Employee badge
                                            October 16, 2019

                                            You need to assign null to the “private String toastMessage = null;” like this “var b: String? = null” as the toast message is having some value it is showing up via binding adapter.

                                            - Abhinav Sutradhar

                                              JournalDev
                                              DigitalOcean Employee
                                              DigitalOcean Employee badge
                                              October 24, 2019

                                              Hi, Thanks for this tutorial… I have implemented this and i got it… But i have a doubt. How can i go to another activity on success?

                                              - Devu Mani

                                                JournalDev
                                                DigitalOcean Employee
                                                DigitalOcean Employee badge
                                                December 12, 2019

                                                when I google MVVM android, this web always displays the first one. It shows that your tutorial is good. Keep up making a good tutorial.

                                                - Muhammad Zawawi Bin Manja

                                                  JournalDev
                                                  DigitalOcean Employee
                                                  DigitalOcean Employee badge
                                                  December 16, 2019

                                                  import com.android.databinding.library.baseAdapters.BR; is showing unused import statement. and in line notifyPropertyChanged(BR.toastMessage); BR > showing errror “Can not resolve symbol BR” Please look after this.

                                                  - Navneet Kumar Gupta

                                                    JournalDev
                                                    DigitalOcean Employee
                                                    DigitalOcean Employee badge
                                                    March 13, 2020

                                                    Horrible waste of time. All of the imports are outdated. Then, when that was finally fixed I get an error in the ActivityMainBinding build file. The project name is hardcoded in and the file cannot be edited. Unable to write the project on my own.

                                                    - Joe

                                                    JournalDev
                                                    DigitalOcean Employee
                                                    DigitalOcean Employee badge
                                                    March 14, 2020

                                                    Hi Joe, This article was written before the introduction of AndroidX. Many updates were released during this time. Gladly, updating the project to the latest SDK is straightforward. Just do a “Migrate to AndroidX” from the Refactor menu. Also, ActivityMainBinding file is auto-generated. So you don’t need to dig too much into it from a coding point of you. A simple clean build should do the job. I would appreciate it if you could read up a bit on Data Binding in Android and then come back with your concerns. I’ve updated the project download file. It should be live in a few hours. Thanks, Anupam

                                                    - Anupam Chugh

                                                      JournalDev
                                                      DigitalOcean Employee
                                                      DigitalOcean Employee badge
                                                      June 4, 2020

                                                      It is really clear to understand. And work with me, a new guy tries to learn MVVM. Thanks a lot

                                                      - Allen

                                                        JournalDev
                                                        DigitalOcean Employee
                                                        DigitalOcean Employee badge
                                                        March 23, 2021

                                                        How did you create a package view under the main package with MainActivity in it ???

                                                        - Pragyanshree Das

                                                          JournalDev
                                                          DigitalOcean Employee
                                                          DigitalOcean Employee badge
                                                          April 1, 2021

                                                          Hello, How can I show the toast message from the string file?(like R.string.xx) I can not find in anywhere for one week. I am about to crazy:( Can you help me please??

                                                          - esra didem

                                                          JournalDev
                                                          DigitalOcean Employee
                                                          DigitalOcean Employee badge
                                                          November 18, 2021

                                                          You can do it like this getResources().getString(R.string.xxx); Use it as the message in your toast.

                                                          - Robo

                                                            JournalDev
                                                            DigitalOcean Employee
                                                            DigitalOcean Employee badge
                                                            April 29, 2021

                                                            Sir how can i start a new activity after click login button plz reply.Im new in mvvm

                                                            - sitansu

                                                            JournalDev
                                                            DigitalOcean Employee
                                                            DigitalOcean Employee badge
                                                            November 25, 2021

                                                            Use Livedata in that case

                                                            - Abdullah Razzaq

                                                              JournalDev
                                                              DigitalOcean Employee
                                                              DigitalOcean Employee badge
                                                              December 4, 2021

                                                              When call login success then you can go another activity via Intent

                                                              - Shafiq Mia

                                                                Join the Tech Talk
                                                                Success! Thank you! Please check your email for further details.

                                                                Please complete your information!

                                                                Become a contributor for community

                                                                Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

                                                                DigitalOcean Documentation

                                                                Full documentation for every DigitalOcean product.

                                                                Resources for startups and SMBs

                                                                The Wave has everything you need to know about building a business, from raising funding to marketing your product.

                                                                Get our newsletter

                                                                Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

                                                                New accounts only. By submitting your email you agree to our Privacy Policy

                                                                The developer cloud

                                                                Scale up as you grow — whether you're running one virtual machine or ten thousand.

                                                                Get started for free

                                                                Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

                                                                *This promotional offer applies to new accounts only.