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.

4.9 (21) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

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

Note: Android studio has a shortcut to create this layout tag: Control/Option + Enter or Right-click + Show context actions ▸ Convert to data binding layout.
Note: Notice the indentation isn’t right after adding these code snippets. To fix it, click the Code menu in Android Studio and select reformat code. This idents the code correctly.

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.

Grocery list screen with cheese listed, at a price of 50 and amount of 5.

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.

data binding files

Note: There’s a separate file for 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 TODOs 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:

  1. 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.
  2. The RecyclerView also has an adapter which gets the items and assigns them to the layout
  3. 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 onCreateshould look now:

Oncreate of activity after binding changes

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?

Grocery

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!

List screen with no items or total.

Don’t worry! In the next step, you’ll add the list and the total labels back to the screen with data binding.