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,
- name
- 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