MVVM using Data Binding in Android

MVVM using Data Binding in Android

Android MVVM It stands for Model, View, ViewModel. Putting everything in a View like Activity or Fragment would lead to difficulties in testing and changing/refactoring the original code. Hence, the use of separation of code and clean structure is recommended. 

Model: This has the data of the Android project. It cannot directly communicate to the View. Normally, it’s recommended to provide the data to the ViewModel by using Observables. 

View: It is the UI of the Android project without any business logic. It observes the ViewModel. 

ViewModel: It acts as a bridge between the Model and the View. It provides a way to transform the data from the Model. It also provides data streams to the View. It uses hooks or callbacks to modify the View. It’ll request for the data from the Model. The viewmodel is a key piece of MVVM as it brings the concept of Presentation Separation, or keeping the nuances of the view apart from the model. The ViewModel helps in keeping the view state, modify the model as the result of actions on the view and trigger events to reflect the changes into the view. 

In order to continue MVVM there is a concept of LiveData that plays an important role in MVVM. LiveData is an observable data holder class. Unlike a traditional observable, LiveData is lifecycle-aware, that means, it follows the lifecycle of app components for example – Activities, Fragments, or Services. This is the reason LiveData only updates app component observers that are in an active lifecycle state, that result in a healthy and crash-less application. 

Differences(MVP) 

  • The Presenter in the Middle Layer is replaced by ViewModel. 
  • The Presenter has dependency on the View while the ViewModel is independent of the View.
  • The Presenter is responsible for updating the View by calling methods. 
  • The ViewModel is responsible for sending data streams. 
  • The Presenter and View are in a one to one relationship. 
  • The View and the ViewModel are in a one to many relationship. 
  • The ViewModel does not have the knowledge that the View is listening to it.

In Android, we have two ways to implement MVVM: 

  • Data Binding 
  • RXJava 

We’ll be using Data Binding here to implement MVVM in Android. 

Google has introduced a Data Binding library in order to bind data directly in the XML layout. 

We are creating a normal Login Example application that prompts for user credentials inputs. 

We will see how the ViewModel intimates the View to show a Toast Message without containing a reference of the View. 

Two Way Data Binding Two-way Data Binding is a way of binding objects to XML layouts so that the layout and the object can both send data to each other. 

Here, the ViewModel can provide data to the layout and observe changes as well. 

For this, we require a BindingAdapter and a user defined attribute in the XML. 

The Binding Adapter will listen to changes in the user defined attribute property. 

We will learn more about Two-way Data Binding by the example below. 

Enable the Data Binding Library for the Android Project 

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

android {
  dataBinding {
    enabled = true
  }
}

This statement will enable Data Binding in the Android Project. 

Add the below dependencies in your build.gradle file : 

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

Model The Model has the employee’s email and password. The below Employee.java class does it:

package com.qait.mvvmdemo.model; 
public class Employee { 
  private String email; private String password; 
  public Employee(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; 
  } 
} 

The Two-way Data Binding provides us a mechanism to bind objects in the XML layouts such that the object can transmit data to the layout, and the layout can transmit data to the object. 

We use below Syntax for Two Way Data Binding 

@={variable}

Layout Following code represents activity_main.xml:

<?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> 
  <variablename="viewModel" type="com.qait.mvvmdemo.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.employeeEmail}" /> 
        <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.employeePassword}" /> 
        <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 should be declared at the top of the layout. Below ViewModel binds the user data to the View.

()-> viewModel.onLoginClicked() trigger the Button click listener lambda created in the ViewModel. The EditText modifies the values in the Model (by View Model).

bind:toastMessage="@{viewModel.toastMessage}" is a user defined attribute as we created for two-way data binding. According to changes in the toastMessage in the ViewModel the BindingAdapter would get called in the View. 

ViewModel Following are the code that an Android app development company normally uses for for the LoginViewModel.java

package com.qait.mvvmdemo.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.qait.mvvmdemo.model.Employee; 
public class LoginViewModel extends BaseObservable { 
  private Employee employee; 
  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 setEmployeeEmail(String email) { 
    employee.setEmail(email); 
    notifyPropertyChanged(BR.employeeEmail); 
  } 
  @Bindable 
  public String getEmployeeEmail() { 
    return employee.getEmail(); 
  } 
  @Bindable 
  public String getEmployeePassword() { 
    return employee.getPassword(); 
  } 
  public void setEmployeePassword(String password) { 
    employee.setPassword(password); 
    notifyPropertyChanged(BR.employeePassword); 
  } 
  public LoginViewModel() { 
    user = new Employee("",""); 
  }
  public void onLoginClicked() { 
    if (isInputDataValid()) 
      setToastMessage(successMessage); 
    else 
      setToastMessage(errorMessage); 
  }
  public boolean isInputDataValid() { 
     return !TextUtils.isEmpty(getEmployeeEmail()) &&
            Patterns.EMAIL_ADDRESS.matcher(getEmployeeEmail()).matches() &&
            getEmployeePassword().length() > 5; 
    }
}

The strategies were brought in the design are executed in the above code with a similar mark. If the XML counterpart of the method doesn’t exist, we need to change the attribute to app:.

The above class can likewise broaden ViewModel. Be that as it may, an Android mobile app development company needs BaseObservable since it changes over the information into streams and advises when the toastMessage property is changed.

We have to characterize the getter and setter for the toastMessage custom quality characterized in the XML. 

Inside the setter, we advise the onlooker (which will be the View in our application) that the information has changed. 

The View(Activity) can characterize the fitting activity. 

BR class is auto-created from information restricting when you revamp the venture The code for the MainActivity.java class is given underneath:

package com.qait.mvvmdemo.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.qait.mvvmdemo.R; 
import com.qait.mvvmdemo.databinding.ActivityMainBinding; 
import com.qait.mvvmdemo.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(); 
    }
}

On account of DataBinding, the ActivityMainBinding class is auto-created from the format. 

The @BindingAdapter technique gets activated at whatever point the toastMessage characteristic on the Button is changed. 

It must utilize a similar characteristic as characterized in the XML and in the ViewModel. 

So in the above application, the ViewModel refreshes the Model by tuning in to the adjustments in the View. 

Likewise, the Model can refresh the view by means of the ViewModel utilizing the notifyPropertyChanged

About the Author

DevLabs Expert Group

DevLabs Expert Group

Related Posts

X