2.4: Data binding basics
1. Welcome
In previous codelabs in this course, you used the findViewById()
function to get references to views. When your app has complex view hierarchies, findViewById()
is expensive and slows down the app, because Android traverses the view hierarchy, starting at the root, until it finds the desired view. Fortunately, there’s a better way.
To set data in views, you’ve used string resources and set the data from the activity. It would be more efficient if the view knew about the data. And fortunately again, this is possible.
In this codelab, you learn how to use data binding to eliminate the need for findViewById()
. You also learn how to use data binding to access data directly from a view.
What you’ll learn
- How to use the Data Binding Library to eliminate inefficient calls to findViewById().
- How to access app data directly from XML.
What you’ll do
- Modify an app to use data binding instead of findViewById(), and to access data directly from the layout XML files.
3. Task: Use data binding to eliminate findViewById()
One solution is to create an object that contains a reference to each view. This object, called a Binding
object, can be used by your whole app. This technique is called data binding. Once a binding object has been created for your app, you can access the views, and other data, through the binding object, without having to traverse the view hierarchy or search for the data.
Data binding has the following benefits:
- Code is shorter, easier to read, and easier to maintain than code that uses findViewById().
- Data and views are clearly separated. This benefit of data binding becomes increasingly important later in this course.
- The Android system only traverses the view hierarchy once to get each view, and it happens during app startup, not at runtime when the user is interacting with the app.
- You get type safety for accessing views. (Type safety means that the compiler validates types while compiling, and it throws an error if you try to assign the wrong type to a variable.)
Change layout file to be usable with data binding
To work with data binding, you need to wrap your XML layout with a <layout>
tag. This is so that the root class is no longer a view group, but is instead a layout that contains view groups and views. The binding object can then know about the layout and the views in it.
Cut the namespace declarations from the <LinearLayout>
and paste them into the <layout>
tag.
Create a binding object in the main activity
Add a reference to the binding object to the main activity, so that you can use it to access views:
- Open the MainActivity.kt file.
- Before onCreate(), at the top level, create a variable for the binding object. This variable is customarily called binding.
The type of binding, the ActivityMainBinding class, is created by the compiler specifically for this main activity. The name is derived from the name of the layout file, that is, activity_main + Binding.
private lateinit var binding: ActivityMainBinding
In onCreate()
, replace the setContentView()
call with the following line of code.
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
4. Task: Use data binding to display data
For this example, instead of setting the name and nickname using string resources, you create a data class for the name and nickname. You make the data class available to the view using data binding.
Step 1: Create the MyName
data class
data class MyName(var name: String = "", var nickname: String = "")
Step 2: Add data to the layout
At the top of the layout, between the <layout>
and <LinearLayout>
tags, insert a <data></data>
tag. This is where you will connect the view with the data.
<data>
<variable
name="myName"
type="com.example.android.aboutme.MyName" />
</data>
Replace android:text="@string/name"
with the code below.
@={}
is a directive to get the data that is referenced inside the curly braces.
android:text="@={myName.name}"
myName
references the myName
variable that you previously defined, which points to the myName
data class and fetches the name
property from the class.
Step 3: Create the data
private val myName: MyName = MyName("Aleks Haecky") // in MainActivity
binding.myName = myName // in onCreate()
This may show an error, because you need to refresh the binding object after making changes. Build your app, and the error should go away.
Step 4: Use the data class for the nickname in the TextView
binding.apply {
myName?.nickname = nicknameEdit.text.toString()
invalidateAll()
...
}
After the nickname is set, you want your code to refresh the UI with the new data. To do this, you must invalidate all binding expressions so that they are recreated with the correct data.
Add invalidateAll()
after setting the nickname so that the UI is refreshed with the value in the updated binding object.