MVVM example

In this example, we'll use Data Binding only.

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.

let's see a very basic example of a login page using the MVVM pattern...

Project structure:

Enable data-binding:
have to enable data-binding in Gradle file:
note: do it in the app-level build file.

android{

   dataBinding{

               enabled = true; 
        }
}

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

Model class:
The model would hold the user details, like user name and password, here User is model class ,

package com.javaoneworld.mvvmsample.model;

public class User {

    private String email;
    private String password;

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

    public String getEmail() {
        return email;
    }

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

    public String getPassword() {
        return password;
    }

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

Data Binding allow us to bind the data in XML layout, so there is no need of findViewById in our acticity class.
Syntax- @={variable}

So there is one more very important thing in data binding case, 
We have to wrap up our layout in <layout>.........</layout> tag,
means that our root tag must be <layout>.

and <layout> contains two thing...

Data
Layout(UI or View)

Data contains two thing,
  1. name
  2. type
Layout:
<?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="viewModel"    
        type="com.javaoneworld.mvvmsample.view_model.LoginViewModel" />

    </data>

    <RelativeLayout     
                android:id="@+id/rootLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".view.MainActivity">
<LinearLayout   
         android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

           <EditText
                android:id="@+id/inEmail"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Email"
                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:text="@={viewModel.userPassword}"/>

            <Button
                android:text="Login"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:onClick="@{()-> viewModel.onLoginClicked()}"
                bind:toastMessage="@{viewModel.toastMessage}"/>

        </LinearLayout>

    </RelativeLayout>
</layout> 

And finally here is ViewModel

ViewModel:

package com.javaoneworld.mvvmsample.view_model;

import android.text.TextUtils;
import android.util.Patterns;

import com.javaoneworld.mvvmsample.model.User;

import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import androidx.databinding.library.baseAdapters.BR;

public class LoginViewModel extends BaseObservable {

    private User user;

    private String successMessage = "Login was successful";
    private String failedMessage = "Login failed";

    @Bindable    private String toastMessage = null;
    @Bindable    private String userEmail;
    @Bindable    private String userPassword;

    public String getToastMessage(){
        return  toastMessage;
    }

    public void setToastMessage(String toastMessage)
    {
        this.toastMessage = toastMessage;

        notifyPropertyChanged(BR.toastMessage);
    }

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

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

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

    }

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

    public LoginViewModel()
    {

        user = new User("","");
    }

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

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


}

Activity:

package com.javaoneworld.mvvmsample.view;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.BindingAdapter;
import androidx.databinding.DataBindingUtil;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import com.javaoneworld.mvvmsample.R;
import com.javaoneworld.mvvmsample.databinding.ActivityMainBinding;
import com.javaoneworld.mvvmsample.view_model.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();
    }
}

No comments:

Post a Comment