Advanced Data Binding in Android: Binding Adapters

In this advanced data binding tutorial, you’ll learn how you can interact directly with the components in your layouts, assign a value and handle events dispatched by the views using binding adapters. By Rodrigo Guerrero.

Leave a rating/review
Download materials
Save for later
Share

The Data Binding Library, part of Android Jetpack, provides an easy way to bind components in your layouts with data sources in your app. You can use a declarative format to make the binding instead of doing it programmatically.

In this tutorial, you’ll build an app named uSpace. This app shows four different lists with information about SpaceX rockets, crew, Dragons and capsules.

Over the course of the tutorial, you’ll learn about:

  • Data binding
  • Using data binding with RecyclerViews
  • Binding adapters
  • Custom binding adapters
  • Conversions
  • Two-way data binding
Note: This tutorial assumes you know the basics of Android development. If you’re new to Android development, check out Beginning Android Development and Kotlin for Android: An Introduction.

Getting Started

Download the materials by clicking the Download Materials button at the top or bottom of this tutorial. Open Android Studio Arctic Fox or later and import the starter project.

Below is a summary of what each package contains:

  • bindingadapters: All classes related to binding adapters.
  • di: Classes for providing dependency injection.
  • network: Classes related to the connection with the API.
  • repository: Repository related code.
  • ui: Classes related to the user interface.
  • utils: Utility methods used in the app.

Open the module build.gradle file. Find the buildFeatures section and enable data binding, as shown below:

buildFeatures {
    viewBinding true
    dataBinding true
}

Build and run the app. You’ll see a screen with the action bar and some tabs as shown below:

uSpace with empty list

Note: If you see an error loading message, make sure your internet connection is turned on.

Notice that the items in the list aren’t showing correctly. Navigate to the other tabs and you’ll see the same behavior. You’ll fix that using data binding and binding adapters.

Introducing Data Binding

The interaction between code and layout used to happen in the activity or fragment using findViewById(). More recently, if you used View Binding, you needed to reference the UI component and use the component methods and listeners to interact between code and layout. Using View Binding, you ended up with a lot of boilerplate code to access and modify the UI components in your layouts.

But with the Data Binding Library from Android Jetpack, you can interact directly with the components in your layouts.

Note: For a more in-depth tutorial about the basics of data binding, check out the following tutorial: Data Binding in Android: Getting Started.

Understanding Data Binding

With data binding, you can use binding expressions to assign values and handle events dispatched by the views. A one-way binding expression has the following form: android:text="@{viewModel.value}". This expressions tells the layout that android:text will have the value viewModel.value. You can use an object, a view model or individual variables to bind the code logic with the layout.

Binding adapters let you bind your code with your layout. Basic binding adapters call setters in the view to set a value, while more advanced adapters add logic to execute while performing data binding. The following diagram shows binding adapters’ place in the data binding process:

Diagram explaining data binding

To use data binding in your apps, you need to:

  1. Enable data binding in your project. You already implemented this step at the beginning of this tutorial.
  2. Add a <layout> in your views.
  3. Add a ViewModel, variables or object you need to the layout.

It’s time to start using data binding in uSpace.

Initializing Data Binding

The Rockets tab needs to show a ProgressBar whenever the app is loading the data. Open fragment_rockets.xml and add a <layout> component as the parent element in the view. All existing elements in the layout need to be children of <layout>. The layout should look as follows:

<?xml version="1.0" encoding="utf-8"?>
<layout>
  <androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.fragments.RocketsFragment">

    <androidx.recyclerview.widget.RecyclerView
      android:id="@+id/rockets_list"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:listitem="@layout/item_rocket" />

    <ProgressBar
      android:id="@+id/progress"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:visibility="gone"
      app:layout_constraintBottom_toBottomOf="parent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent" />

  </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

Add <data> as a child of <layout>. It’ll hold the variables you can use in the layout file. You can add one or multiple variables in the layout. In this case, you need to add a Boolean with the name loading, as follows:

<data>
  <variable
    name="loading"
    type="Boolean" />
</data>

variable has two attributes:

  1. name: You can access the provided object in this layout with this name.
  2. type: If you use a custom object or view model, you need to add its complete package name.

Later on, you’ll add a custom binding adapter to use this variable to display or hide the progress bar on this screen.

Whenever you want to use data binding in your layouts, perform these steps. However, it’s more complicated to use data binding in RecyclerViews so in following section, you’ll learn how to set up RecyclerView‘s adapters to use data binding.

Binding Data in RecyclerViews

To start using data binding in a RecyclerView, open item_capsule.xml and add <layout> as the root element in the layout. Then add <data> with a variable of type Capsule in it, as shown below:

<data>
  <variable
    name="capsule"
    type="com.raywenderlich.android.uspace.ui.models.Capsule" />
</data>

Once you add the variable to the layout, you need to set its value in the adapter. Android Studio creates a BR class that includes the reference to the variable you added. Be sure to rebuild your project before continuing.

Note: You can find the BR class file in your app ▸ build ▸ generated ▸ source ▸ kapt▸debug(buildVariant) ▸ com.raywenderlich.android.uspace folder.

Open CapsuleAdapter.kt and modify bind() as follows:

fun bind(capsule: Capsule) {
  binding.setVariable(BR.capsule, capsule)
}

binding contains the reference to the list item’s layout. Using setVariable(), assign the value of the object it needs to the layout. BR.capsule is the name of the variable you’ll set and capsule is the value you’ll pass to the layout.

Next, import the following class:

import com.raywenderlich.android.uspace.BR

You’ve completed initializing data binding for the Capsules list. The time has come to start using binding adapters.

Understanding Binding Adapters

Binding adapters are responsible for binding the code to your layout elements. They’ll call the UI element’s setters to assign the value, execute some custom logic or listen to user interaction in the view. You’ll use these three types of binding adapters in the following sections.