1 of 51

Data binding with MVVM

2 of 51

Agenda

  • MVVM
  • Data binding
  • 2-way data binding
  • Event callbacks
  • Binding Adapters
  • Observable Objects
  • Live Data

3 of 51

What is MVVM?

  • Model
  • View
  • ViewModel

4 of 51

Model

  • It has the data, state and business logic.
  • Talk to other layers for api calling or database operations.
  • Acts as a data access layer.
  • Not tied to the view or view controller.

5 of 51

View

  • View to be displayed to the user.
  • Bind to the ViewModel for data and action callbacks.
  • Multiple views can bind to a single view model and vice versa.

6 of 51

ViewModel

  • Middle layer between Model and View.
  • Wraps the data and send it to View.
  • Observe callbacks of view events and send it to Model.
  • Does not have a reference to the View

7 of 51

How to achieve it?

8 of 51

Android data binding

9 of 51

10 of 51

Get started with data binding

11 of 51

Any other benefit?

12 of 51

Boilerplate code

TextView textView = findViewById(R.id.txv_user_name);

textView.setText(model.getUserName());

13 of 51

Boilerplate code

EditText editText = findViewById(R.id.edt_username);

model.setUserName(editText.getText().toString());

14 of 51

Reduced Code with data binding

<TextView

android:text="@{viewModel.userName}"/>

15 of 51

Reduced Code with data binding

<EditText

android:text="@={viewModel.username}"/>

16 of 51

Login Page Example

  • Have 2 fields username and password.
  • Have login button.
  • On click of login, show error on field if validation fails.

17 of 51

Login Page Example

Model

18 of 51

Model

public class LoginForm {

public String username;

public String password;

}

19 of 51

Model

public boolean isUsernameValid() {

return !TextUtils.isEmpty(username) && username.length() >= 4;

}

public boolean isPasswordValid() {

return !TextUtils.isEmpty(password) && password.length() >= 4;

}

20 of 51

Login Page Example

ViewModel

21 of 51

ViewModel

public class LoginViewModel {

public LoginForm loginForm = new LoginForm();

public void onLoginClick() {

isValid();

}

}

22 of 51

ViewModel

private boolean isValid() {

boolean passwordValid = loginForm.isPasswordValid();

boolean usernameValid = loginForm.isUsernameValid();

return usernameValid && passwordValid;

}

23 of 51

Login Page Example

View

24 of 51

View

<layout>

<data>

<variable name="loginViewModel"

type="com.example.viewModel.LoginViewModel"/>

</data><!--View root layout-->

</layout>

25 of 51

View

<EditText

android:id="@+id/edt_username"

android:text="@={loginViewModel.loginForm.username}"/>

<EditText

android:id="@+id/edt_password"

android:text="@={loginViewModel.loginForm.password}"/>

26 of 51

View

<Button

android:id="@+id/btn_login"

android:onClick="@{() -> loginViewModel.onButtonClick()}"/>

27 of 51

Login Page Example

  • Have 2 fields username and password.
  • Have login button.
  • On click of login, show error on field if validation fails.

28 of 51

ViewModel

public LoginForm loginForm = new LoginForm();

public ObservableField<String> usernameError =

new ObservableField<>();

public ObservableField<String> passwordError =

new ObservableField<>();

29 of 51

ViewModel

if (!usernameValid){

usernameError.set("Please enter valid username");

}

if (!passwordValid){

passwordError.set("Please enter valid password");

}

30 of 51

ViewModel

@BindingAdapter("error")

public static void setError(EditText editText, String error) {

editText.setError(error);

}

31 of 51

View

<EditText

android:id="@+id/edt_username"

app:error="@{loginViewModel.usernameError}"/>

<EditText

android:id="@+id/edt_password"

app:error="@{loginViewModel.passwordError}"/>

32 of 51

How view is connected to ViewModel?

33 of 51

Connect DataBinding and ViewModel

setContentView(R.layout.activity_login);

34 of 51

Connect DataBinding and ViewModel

setContentView(R.layout.activity_login);

ActivityLoginBinding loginBinding = DataBindingUtil.setContentView(this, R.layout.activity_login);

LoginViewModel loginViewModel = new LoginViewModel();

loginBinding.setLoginViewModel(loginViewModel);

35 of 51

Recap..

36 of 51

Recap..

  • Added data and business logic in Model.

37 of 51

Recap..

  • Added data and business logic in Model.
  • Added model, click event callback, BindingAdapter in ViewModel.

38 of 51

Recap..

  • Added data and business logic in Model.
  • Added model, click event callback, BindingAdapter in ViewModel.
  • Added a variable of ViewModel in View.

39 of 51

Recap..

  • Added data and business logic in Model.
  • Added model, click event callback, BindingAdapter in ViewModel.
  • Added a variable of ViewModel in View.
  • Connected View to ViewModel in Activity.

40 of 51

Observable Objects

41 of 51

Observable Objects

  • A class which extends BaseObservable
  • Class will be responsible to notify the changes
  • Assign Bindable annotation to property getter
  • Call notifyPropertyChanged() when required

42 of 51

ViewModel

public class LoginViewModel extends BaseObservable {

private String userName;

@Bindable

public String getUserName() {

return userName;

}

}

43 of 51

ViewModel

public void onLoginClick() {

if (isValid()) {

userName = "Test user name";

notifyPropertyChanged(BR.userName);

}

}

44 of 51

LiveData

45 of 51

LiveData

  • Connect activities/fragment to the data
  • Ensures your UI matches your data state
  • Lifecycle aware
  • No memory leaks
  • No crashes due to stopped activities
  • No more manual lifecycle handling
  • Always up to date data
  • Proper configuration changes

46 of 51

ViewModel

public class LoginViewModel {

private MutableLiveData<String> userNameLiveData =

new MutableLiveData<>();

public MutableLiveData<String> getUserNameLiveData() {

return userNameLiveData;

}

}

47 of 51

ViewModel

public void onLoginClick() {

if (isValid()) {

userNameLiveData.setValue("Test name");

}

}

48 of 51

Activity

Observer<String> observer = new Observer<String>() {

@Override

public void onChanged(@Nullable String username) {

Toast.makeText(LoginActivity.this, username,

Toast.LENGTH_SHORT).show();

}

};

49 of 51

Activity

loginViewModel.getUserNameLiveData().observe(this, observer);

50 of 51

Questions??

51 of 51

Thank You