Data Binding in Android: Getting Started
In this Android Data Binding tutorial, you’ll learn how to link UI components to data in your app using a declarative format. By Evana Margain Puig.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Data Binding in Android: Getting Started
20 mins
- Getting Started
- Why Use Data Binding
- How Data Binding Works
- Configuring for Data Binding
- Transforming a Standard XML Layout Into a Data Binding Layout
- Cleaning Up The Errors
- Autogenerated Binding classes
- Enabling Data Binding in Activities, Fragments and Related Code
- Adding Data Binding to Activities
- Binding the View
- Accessing The View Children
- Getting Rid of Errors
- Adding Data Binding to Adapters
- Value Binding
- Layout Variables
- Layout Expressions
- Binding Values in Activities
- Binding Values in Adapters
- Where to Go From Here?
Cleaning Up The Errors
The constraint layout tag now shows a warning regarding redundant declarations. To fix that, remove the three lines starting with xmlns:android
, xmlns:app
and xmlns:tools
Repeat the above steps once again in grocery_list_item.xml
Build and run. Try to add, edit and delete a few items and see that nothing crashes.
Autogenerated Binding classes
Earlier, you learned that the Data Binding Library automatically generates classes for binding. Now, you can see the generated classes. Take a look at the screenshot below to see where they are in the file structure.
Java(generated)
that contains different code instances. You won’t edit them in this tutorial, but it’s good to know they exist.Enabling Data Binding in Activities, Fragments and Related Code
Now that the app and layouts know they’ll use data binding, you have to make changes to your code. As mentioned earlier, you’ll work with the three files inside the view folder.
Adding Data Binding to Activities
Open GroceryListActivity.kt. Notice there are several TODO
s in the file. You’ll replace them from top to bottom as you learn how data binding configures the XML layouts with the code.
The first TODO
, in line 53, tells you to remove the view items, which are Button, RecyclerView and TextView. All of these objects make reference to items in layout.activity_grocery_list. With the Data Binding Library, you don’t need to create variables for each one because the library does that for you.
Replace those three lines with the following line of code.
private lateinit var binding: ActivityGroceryListBinding
This code creates an instance of the automatically created binding class for activity_grocery_list.xml. Later, you’ll initialize through onCreate.
When you add this code, Android Studio asks you to import some dependencies. Do as suggested. Don’t worry about the errors because you’ll fix them in a minute.
import com.raywenderlich.android.gobuy.databinding.ActivityGroceryListBinding
By importing this class, you make a reference to the binding class from the previous step.
Binding the View
Next, replace the call to setContentView(R.layout.plain_activity)
in onCreate
with:
binding = DataBindingUtil.setContentView(this, R.layout.activity_grocery_list)
This code uses a Data Binding Library class called DataBindingUtil to set the content view. This line is very similar to the one you removed before, but now it associates the code with data binding.
3. Remove the findViewById
lines of code.
Now you can remove the three lines with findViewById
in onCreate
, which are likely showing an error after your last change. You can remove these lines because you don’t need to look for the views by IDs since you’ll populate them through layout variables.
Before data binding, findViewById()
was the most common way to connect the layout and code. It caused many problems because errors happened at runtime, and sometimes those errors weren’t detected until after production.
Accessing The View Children
Remove the remaining lines of code in onCreate
and replace them with the following:
// 1
binding.rvGroceryList.layoutManager = LinearLayoutManager(this)
// 2
binding.rvGroceryList.adapter = GroceryAdapter(viewModel.groceryListItems, this, ::editGroceryItem, ::deleteGroceryItem)
// 3
binding.addItemButton.setOnClickListener {
addGroceryItem()
}
Here’s a step-by-step breakdown:
- The first part binds the RecyclerView to the corresponding layout manager in the XML file. RecyclerViews are a separate topic, but on a high level, the linear layout manager is the item in the view that displays the list of grocery items.
- The RecyclerView also has an adapter which gets the items and assigns them to the layout
- Finally, you bind the addItemButton to its click method.
Are you a bit confused by all the TODO
items? Take a look at the following screenshot to see how your onCreate
should look now:
Notice the last three methods still have errors. You’ll fix these in the next section.
Getting Rid of Errors
Replace the last lines inside deleteGroceryItem with:
//groceriesTotal.text = viewModel.getTotal().toString()
binding.rvGroceryList.adapter?.notifyDataSetChanged()
The line above tells the RecyclerView, which displays your list of groceries, that you removed an item in the list and it needs to refresh. You’ll fix the total amount later in the tutorial, so comment out that line for now.
You may notice the change needed for onDialogPositiveClick
is very similar to the one you just did. Change the line with an error to:
binding.rvGroceryList.adapter?.notifyDataSetChanged()
This line tells the RecyclerView that whenever you click the add button in the alert, your list has changed.
As you did in the past method, comment out the code for the total until you come back to it later:
//groceriesTotal.text = viewModel.getTotal().toString()
You’re down to two errors in the file! Both refer to the addItemButton
. As you might have guessed, you need to change those lines to make reference to the binding object. Replace the line with an error inside onDialogPositiveClick
to:
Snackbar.make(binding.addItemButton, "Item Added Successfully",
Snackbar.LENGTH_LONG).setAction("Action", null).show()
And the error in onDialogNegativeClick with:
Snackbar.make(binding.addItemButton, "Nothing Added",
Snackbar.LENGTH_LONG).setAction("Action", null).show()
The difference in both these methods is now addItemButton
is associated with the binding through binding.addItemButton
.
You resolved all of the errors! You can finally test your changes.
Build and run. Test it as you did in the previous sections. Notice anything different?
The app works as before, but the total doesn’t show. Don’t worry! This happens because of the two lines of code you commented out above. You’ll fix that next.
Adding Data Binding to Adapters
Next, you’ll connect GroceryAdapter to the binding classes, as you did for the GroceryListActivity. The process is pretty straightforward and involves very similar steps.
Open GroceryAdapter.kt and starting from the bottom, replace the whole ViewHolder with the following code:
class ViewHolder(val binding: GroceryListItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: GroceryItem) {
binding.apply {
//itemName = "${item.amount}x: ${item.itemName}"
//price = item.price.toString()
}
}
}
Look at the code before and after. Previously, the ViewHolder only made reference to the views. By applying the binding with the new code, you also set the value for the item and the price. Two lines have been commented out because they would throw errors that you’ll fix later.
After this change, onBindViewHolder
stops recognizing the view objects because they don’t exist anymore. To fix that, replace the code in this method with the following:
holder.bind(items[position])
holder.binding.buttonEdit.setOnClickListener { itemEditListener(position) }
holder.binding.buttonDelete.setOnClickListener { itemDeleteListener(position) }
With this code, you assign the listeners to the edit and delete buttons. You also bind each item from the list in the recycler view.
Make one last change in the adapter. Replace the onCreateViewHolder
code with:
val layoutInflater = LayoutInflater.from(context)
val binding: GroceryListItemBinding = DataBindingUtil.inflate(layoutInflater,
R.layout.grocery_list_item,
parent, false)
return ViewHolder(binding)
Since the adapter is a class you use to display each of the rows in the recycler view, and you tied the view holder to the binding classes, the layout now uses the binding. With this code, you create an instance of the view holder for the corresponding row through the binding classes.
Build and run. Test the app and add an item. Oh no! The list text is gone!
Don’t worry! In the next step, you’ll add the list and the total labels back to the screen with data binding.