Currently, it can be said that MVVM architecture in Android is the best architecture to implement applications against architectures such as MVP or MVC. This tutorial will discuss and implement the Android MVVM architecture template in our Android application. We have already discussed the MVP architecture pattern in Android.
Types of architecture in Android
(MVVM (Model, View, View Model
(MVP (Model, View, Presenter)
(MVC (Model, View, Controller)
What is the MVVM architecture?
MVVM stands for Model, View, ViewModel.
Model, View, ViewModel (MVVM) is a program architecture template proposed by John Gusman as an alternative to MVC and MVP templates when using Data Binding technology. First, we consider this template’s description and analyze each of its components. MVVM is a software architecture design template that facilitates the separation of the user interface from the business logic and the application’s data model.
Model
The model layer can include data access (Repository, repositories, APIs), Entity classes, etc. The model is a data provider for updating data. Data can be retrievable from various sources, for example:
- REST API
- Realm DB
- SQLite DB
- Handles broadcast
- Shared Preferences
- Firebase
- And, etc.
The model does not know anything about View or ViewModel and exists independently. If you transfer an Android application on the MVC or MVP template to MVVM, the model layer will probably not need to be change.
View
The view is what the user sees, and in Android programming, views are typically definable in XML. And are mostly observable in the Fragment, Activity, or View classes. In many Android applications, code unrelatable to View, especially business logic, is often confusable with Fragments and Activities. Which can be very difficult to develop or maintain.
MVVM tackles this problem by keeping Fragments and Activities only as part of the View layer. They just have to set the view and connect the ViewModel to the View (with tools like RxJava).
Unlike View, MVC has no model information. view is only aware of the ViewModel with which it fills in its data for display.
The view must be free of display logic (date formatting, rules for showing / hiding an element, etc.), which will be present in ViewModel instead. The view can request the ViewModel to operate, which may usually update the model based on user input.
For example, View is responsible for handling the following topics:
- Menus
- Permissions
- Event listeners
- Showing dialogs, Toasts, Snack bars
- Working with Android View and Widget
- Start Activities
- All functionality that is related to the Android Context
ViewModel
ViewModel contains the data required for View. As the name implies, the ViewModel is the View and the Model bridge. Extracts its data from the model layer and converts it for display. ViewModel maintains the active state of the program. Exposes this operation to the View and provides the interface for updating the model. ViewModels are a kind of POJO, which means that they are easily testable, one of their main advantages.
ViewModel has the following responsibilities:
- Exposing data
- (Exposing state (progress, offline, empty, error, etc
- Handling visibility
- Input validation
- Executing calls to the model
- Executing methods in the view
ViewModel only needs to know about the Context of the application. Context The program can include:
- Start a service
- Bind to a service
- Send a broadcast
- Register a broadcast receiver
- Load resource values
And may not include the following:
- Show a dialog
- Start an activity
- Inflate a layout
Difference between MVVM and MVP:
- ViewModel sits in the middle layer instead of the Presenter.
- The presenter refers to View. ViewModel is not like this.
- ViewModel sends data streams.
- Presenter and View are in a 1: 1 relationship.
- View and ViewModel are in a 1-to-many relationship.
- ViewModel does not know that View is listening.
Difference between MVVM and MVC:
MVVM has several concepts with the more common model (MVC) Model View Controller, so those who are already familiar with or have worked with MVC should be able to work with MVVM easily. What is different is how they communicate and how they are aware of each other.
Benefits of MVVM
Viewmodels make Display Logic easier to test:
Viewmodels allow screen logic to be tested without being seen moment by moment. Android development allows more tests to be written in JUnit and run locally, not in Android JVM (emulator or device), meaning that the tests run much faster.
Separation of relations:
Fragile code causes program maintenance nightmares. Suppose we start developing an application without any architecture. In that case, we will cause more errors in the program, and when we want to add a new feature to the program, we will be confused. So the speed of program development will be very slow and will cause the customer to be dissatisfied with the program development process. One of the most important benefits that we often see in Android applications is the integrated Activities and Fragments that include business logic and direct interaction with the database or API, which comes with all the View code. Also MVVM helps maintain a clean, consistent, and fully paired architecture, keeping Activities and Fragments merely part of The View.
Improves code reuse:
The user interface can be updated without touching Business Logic:
Two ways to implement MVVM on Android:
- Data Binding
- RxJava
In this article, we will use Data Binding.
Google introduced the Data Binding Library to link data directly in the XML Layout.
We want to create a simple example of a log-in program that requests input from a user. We will see how the ViewModel notifies the View when to display the message (Toast) without holding or referring to the View.
How can I inform some classes without referring to them?
This can be in three different ways:
- Using Two Way Data Binding
- Also Using LiveData
- Using RxJava
Two Way Data Binding:
Two Way Data Binding is a technique for connecting your objects to the XML Layout so that Object and Layout can send both data to each other.
In our example, ViewModel can send data to the layout and view changes.
We need a BindingAdapter and custom attribute defined in XML to do this.
BindingAdapter can listen for feature changes.
Learn more about Two Way Data Binding through the example below.
Example of the MVVM project structure in Android:
Add Data Binding Library
android {
dataBinding {
enabled = true
}
}
Add dependencies
implementation 'android.arch.lifecycle: extensions: 1.1.0'
Model
Holds the user’s email and password model. The User.java class does this:
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 link objects in the XML Layout so that the Object can send the data to the Layout and vice versa.
Nt Syntax For Two Way Data Binding @ = {variable
Layout
The code for activity_main.xml is as follows:
<? 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 >
Here our ViewModel connects the data to the View. ViewModel.onLoginClicked () () This button is defined and called lambda in ViewModel.
ViewModel
The LoginViewModel.java login code is as follows:
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 above class can also extend ViewModel. But we need BaseObservable because it converts data into a stream and gets notified when the toastMessage property changes.
For the custom toastMessage attribute defined in XML, we need to define Setter and Getter.
Inside the Setter, we notify the Observer that the data has changed. Our view (our activity) can define the appropriate action.
The MainActivity.java class code is as follows:
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 of the Layout is created automatically. The BindingAdapter method is activated when the toastMessage properties defined in the button change. Must use the same attribute as defined in XML and ViewModel.
So in the above program, ViewModel updates the model by listening to the changes in View. Also, the model can update the View via ViewModel using notifyPropertyChanged.
You can see the output of the above program below.
Another example of MVVM in Android
- RxJava
- Retrofit
- Dagger 2
- Picasso
- AndroidAnnotations
- Lombok
You can see this example at the following link:
Conclusion:
In this article, we got acquainted with the MVVM architecture in Android. We compared it with MVC architecture and MVP architecture. We got acquainted with the features and performance of MVVM and realized that using it is very useful. And gives a general path to our application and makes it very easy for us to add a new feature to our program, gives high testability, and Improves program maintenance.