Android Data Binding and MVVM Architecture Design
You might have heard of Data Binding. It is a library as part of the Android Jetpack that binds UI components to data sources in the XML layout and minimizes the required code for the application’s logic. It has the ability of automatic UI update whenever data is changed and you can say goodbye to the very familiar findViewById
🤗 … so more than code readability it helps to reduce null pointer exceptions and memory leaks, but consider that the errors will be caught in the compile-time. Although the layout expression language gives you a lot of power, it is best to avoid nesting complex logic inside views. Complex expressions will make your layout harder to read and maintain.
Now let’s get into coding 👩💻 …
Prerequisite
Model-view-viewmodel (MVVM) architecture design
Setup Instructions
First of all, in this sample project, the user enters a valid id which is between 1 and 5000, and then, as a result, a Photo and its title inside the activity will be shown (with a network call).
Add the following snippet inside the app’s build.gradle
file:
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'android {
...
dataBinding {
enabled = true
}
}dependencies {
...
//the compiler version must be the same as the gradle version
kapt "com.android.databinding:compiler:$gradle_version"
}
If you are using Kotlin, you have to add Data Binding’s compiler as a dependency like the above code or you can enable it inside gradle.properties
file of the project properties section as shown below:
android.databinding.enableV2=true
The next step to enable Data Binding is to wrap your whole XML layout with a <layout>
tag as a parent. Then if you build the project, it will generate all the needed classes, which enables Data Binding. From now, all your changes related to Data Binding will be effective and there is no need to rebuild the project for each change. For binding UI components to data sources add a <data>
tag inside the <layout>
tag as per below:
Layout variables are used to write layout expressions. Layout expressions are placed in the value of element attributes and they use the @{}
syntax. Here are some examples:
android:text="@{photoModel.title}"
android:onClick="@{photoViewModel::onGetPhotoButtonClick}"
android:visibility="@{user.age > 18 ? View.INVISIBLE: View.VISIBLE}"
android:onClick="@{() -> photoViewModel.onGetPhotoButtonClick()}"
I have defined two variable
s inside the <data>
tag. One with the name of photoModel
and type of my current Model class inside the project which is a data class, called Photo
as the below snippet:
And the other variable is photoViewModel
with the type of my ViewModel class,PhotoViewModel
.
The @={}
syntax is used for Two-way Data Binding in which the layout and the object can both send data to each other and I have used it for the <EditText>
due to getting the input automatically and for that, you need to create a ViewModel class for your activity or fragment.
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.
Inside the ViewModel class, I needed to get the Id from UI, I defined an Id variable so that by pressing a button the process could start. So, I have defined the onGetPhotoButtonClick()
function. Whatever value is entered in that edit text, it will be assigned automatically to the photoViewModel.id
value which is var id: Int = 0
inside the below class:
As our architecture pattern says the View Model class will interact with the Repository class to send the Id to the server for getting the photo and if the response is successful we will get our photo model. For this purpose, I have defined the PhotoListener
class:
For inflating the activity’s layout we’re going to follow the below new structure:
As you can see the binding variable name (ActivityPhotoBinding) is a combination of the name of the XML layout (activity_photo) without underline, with capitalized letters, and the Binding Keyword at the end. The purpose of this binding variable is to set those layout variables which are declared in the <data>
block and one of our variables will be photoViewModel
. After creating the instance of photoViewModel
set its value inside the activity (it’s going to be as our binding view model and it will bind the data with the UI) as shown in the following code snippet:
val photoViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(PhotoViewModel::class.java)
photoBinding.photoViewModel = photoViewModel
...
As I have overridden the methods of PhotoListener
inside the activity, when the response is successful the below function is called and then we can set the given Photo from the server to the photoModel
‘s value:
override fun onSuccess(photoResponse: LiveData<Photo>) {
photoResponse.observe(this, Observer {
progress_bar.hide()
if (it != null) {
photoBinding.photoModel = it
showToast(getString(R.string.success))
} else {
showToast(getString(R.string.error))
}
})
}
When you’re using Data Binding, setting values into your views
with a normal approach is like the way we set the <Button>
or <EditText>
, but sometimes you want to do something special in your setting methods. For example, we have an <ImageView>
and we want to define its resource, we can do it by defining it via a @BindingAdapter
in our code for it:
And then inside your XML layout for that <ImageView>
add the below snippet:
app:imageResource="@{photoModel.thumbnailUrl}"
That was a simple example of using Data Binding with MVVM architecture design 🤩 … You can find the whole code at the below repository: