Exploring The Data Binding Library For Android

Latitude Technolabs
9 min readJun 4, 2021

--

Exploring The Data Binding Library For Android — Latitude Technolabs

All Android developers want to reduce their code size and want to make cleaner code, so this is necessary to bind your UI component to data.

In this article, learn how to set up your development environment to work with the Data Binding Library, including using Android Studio to write data binding code.

The Android data binding library gives us a way to bind data in an Android layout. It helps us remove all boilerplate codes findViewById() so you don’t have to manually update the views in code. So, in short, it helps us to speed up the process in android development.

What Is Android Data Binding?

The Android Data Binding library is a support library that lets you use a declarative style instead of programming to connect UI components in your layouts to data sources in your android app.

Data Binding in Android

As android developers, all are aware that we’re always looking for methods to make our code smaller and clearer. Aside from that, using boilerplate code like setText(), setImageResource(), and so on, you may populate your UI component with data.

There are many ways to avoid these things, and you could use the UI directly from a java or kotlin file, but the Kotlin extension is no longer supported.

ViewBinding and Data Binding are native Android features that allow you to access your UI components and link them directly to the data source.

  • ViewBinding

ViewBinding is an Android feature that allows you to easily access any UI components via created Binding classes. When view binding is enabled in a build.gradle file, binding classes are generated, which include all UI component references.

If the layout file name is Cricket_Score.xml, then it will create its class with a name like CricketScoreBinding.

package com.example.databindingsample

import android.os.Bundle

import androidx.appcompat.app.AppCompatActivity

import androidx.databinding.DataBindingUtil

import com.example.databindingsample.databinding.ActivityMainBinding

import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint

class MainActivity : AppCompatActivity() {

private lateinit var activityMainBinding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

activityMainBinding = DataBindingUtil.setContentView(this,R.layout.activity_main,)

}

}

In a Fragment, ViewBinding:

package com.example.databindingsample.ui

import android.os.Bundle

import android.view.LayoutInflater

import android.view.View

import android.view.ViewGroup

import androidx.fragment.app.Fragment

import com.example.databindingsample.databinding.FragmentSampleBinding

class SampleFragment : Fragment() {

private var _binding: FragmentSampleBinding? = null

private val binding get() = _binding!!

override fun onCreateView(

inflater: LayoutInflater, container: ViewGroup?,

savedInstanceState: Bundle?

): View {

// Inflate the layout for this fragment

_binding = FragmentSampleBinding.inflate(inflater, container, false)

return binding.root

}

override fun onDestroyView() {

super.onDestroyView()

_binding = null

}

}

Databinding

Databinding is an Android support library that allows you to easily tie your UI components to data sources such as ViewModel.

What Are The Data Binding Types In Android?

There are two types of Data Binding: View binding and data binding. ViewBinding is an Android feature that allows you to use created Binding classes to directly access all of the UI components. Databinding is an Android support library that allows you to easily tie your UI components to data sources such as ViewModel. More details are added in the later article.

Android working with Data Binding

Android DataBinding is a means to connect the UI to business logic, allowing the user interface to update itself without the need for manual intervention. It reduces lots of boilerplate code.

Before starting, we have to enable DataBinding.

  • Enabling DataBinding

To get started with this, open build.gradle and enable databinding under the android component.

app/build.gradle

android {

dataBinding {

enabled = true

}

compileSdkVersion 27

defaultConfig {

applicationId “info.latitudetechnolabs.databinding”

minSdkVersion 16

// ..

}

}

Now, enabling databinding in layout.

<layout …>

<data>

<variable

name=”…”

type=”…” />

</data>

<LinearLayout …>

<! — YOUR LAYOUT HERE →

</LinearLayout>

</layout>

The @ annotation should be used to bind a value. User name and email are tied to TextView using @user.name and @user.email in the layout below.

activity_main.xml

<?xml version=”1.0" encoding=”utf-8"?>

<layout xmlns:android=”http://schemas.android.com/apk/res/android">

<data>

<variable

name=”user”

type=”info.latitudetechnolabs.databinding.User” />

</data>

<LinearLayout 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”

android:orientation=”vertical”

android:padding=”@dimen/fab_margin”

app:layout_behavior=”@string/appbar_scrolling_view_behavior”

tools:context=”.MainActivity”

tools:showIn=”@layout/activity_main”>

<TextView

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@{user.name}” />

<TextView

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@{user.email}” />

</LinearLayout>

</layout>

Now, the databinding is integrated into the layout file now to rebuild the project so it can generate classes that are necessary. According to the naming standard for the layout file where binding is enabled, the produced binding classes are named according to the naming standard for the layout file. ActivityMainBinding will be the produced binding class for the layout activity main.xml.

To bind data in the UI, you must first inflate the binding layout using the produced binding classes.

ActivityMainBinding inflates and binds the layout initially. setUser() is a method that connects the User object to the layout.

MainActivity.java

import android.databinding.DataBindingUtil;

import android.os.Bundle;

import android.support.v7.app.AppCompatActivity;

import info.latitudetechnolabs.databinding.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

private User user;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

// setContentView(R.layout.activity_main);

ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

user = new User();

user.setName(“Your username”);

user.setEmail(“Your Email”);

binding.setUser(user);

}

}

Now you can see that your user details will be shown in textviews.

<Include> layouts with DataBinding

Now we will enable databinding when we have layouts included.

To enable databinding, <layout> tag used in activity_main.xml. There are also <variable> and <data> tags that are used to bind the object.

activity_main.xml

<?xml version=”1.0" encoding=”utf-8"?>

<layout xmlns:bind=”http://schemas.android.com/apk/res/android">

<data>

<variable

name=”user”

type=”info.latitudetechnolabs.databinding.User” />

</data>

<android.support.design.widget.CoordinatorLayout 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=”.MainActivity”>

<android.support.design.widget.AppBarLayout

android:layout_width=”match_parent”

android:layout_height=”wrap_content”

android:theme=”@style/AppTheme.AppBarOverlay”>

<android.support.v7.widget.Toolbar

android:id=”@+id/toolbar”

android:layout_width=”match_parent”

android:layout_height=”?attr/actionBarSize”

android:background=”?attr/colorPrimary”

app:popupTheme=”@style/AppTheme.PopupOverlay” />

</android.support.design.widget.AppBarLayout>

<include

android:id=”@+id/content”

layout=”@layout/content_main”

bind:user=”@{user}” />

<android.support.design.widget.FloatingActionButton

android:id=”@+id/fab”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_gravity=”bottom|end”

android:layout_margin=”@dimen/fab_margin”

app:srcCompat=”@android:drawable/ic_dialog_email” />

</android.support.design.widget.CoordinatorLayout>

</layout>

The <layout> tag is used once more in content main.xml to facilitate data binding. <data>, <variable>, and <layout> are necessary in parent and included layouts.

content_main.xml

<?xml version=”1.0" encoding=”utf-8"?>

<layout xmlns:android=”http://schemas.android.com/apk/res/android">

<data>

<variable

name=”user”

type=”info.latitudetechnolabs.databinding.User” />

</data>

<LinearLayout 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”

android:orientation=”vertical”

android:padding=”@dimen/fab_margin”

app:layout_behavior=”@string/appbar_scrolling_view_behavior”

tools:context=”.MainActivity”

tools:showIn=”@layout/activity_main”>

<TextView

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@{user.name}” />

<TextView

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@{user.email}” />

</LinearLayout>

</layout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);

setSupportActionBar(binding.toolbar);

User user = new User();

user.setName(“Your username”);

user.setEmail(“Your email”);

binding.setUser(user);

}

}

Binding Click Listeners / Event Handling

Not only can we link data to UI elements, but we can also bind click and other events. You’ll need to develop a class with the appropriate callback methods to bind a click event.

A class that handles the FAB click event is shown below.

public class MyClickHandlers {

public void onFabClicked(View view) {

Toast.makeText(getApplicationContext(), “FAB clicked!”, Toast.LENGTH_SHORT).show();

}

}

We use the same <variable> tag with the path to the handler class to bind the event.

<layout xmlns:bind=”http://schemas.android.com/apk/res/android">

<data>

<variable

name=”handlers”

type=”info.latitudetechnolabs.databinding.MainActivity.MyClickHandlers” />

</data>

<android.support.design.widget.CoordinatorLayout …>

<android.support.design.widget.FloatingActionButton

android:onClick=”@{handlers::onFabClicked}” />

</android.support.design.widget.CoordinatorLayout>

</layout>

The method must return Boolean type instead of void.public boolean onButtonLongPressed()

Observables for UI Updating

Observables allow you to automatically synchronize the UI with the data without having to invoke setter methods. When the value of a property in an object changes, the UI will be changed. Extend the BaseObservable class to make the object observable.

The modified User class, which extends BaseObservable, is shown below. You’ll notice something interesting here. After assigning new values, notifyPropertyChanged is invoked.

package info.latitudetechnolabs.databinding;

import android.databinding.BaseObservable;

import android.databinding.Bindable;

public class User extends BaseObservable {

String name;

String email;

@Bindable

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

notifyPropertyChanged(BR.name);

}

@Bindable

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

notifyPropertyChanged(BR.email);

}

}

Using ObservableFields to update the UI

You can use ObservableFields to update the UI if your object class has fewer properties to update or if you don’t want to observe every field in the object. You can specify the variable as an ObservableField, and the UI will be changed when new data is entered.

ObservableFields can be used to modify the same User class, as seen below.

package info.latitudetechnolabs.databinding;

import android.databinding.ObservableField;

public class User {

public static ObservableField<String> name = new ObservableField<>();

public static ObservableField<String> email = new ObservableField<>();

public ObservableField<String> getName() {

return name;

}

public ObservableField<String> getEmail() {

return email;

}

}

Instead of utilizing the setter method to change the values, you must directly assign a new value to the property.

public class MyClickHandlers {

Context context;

public MyClickHandlers(Context context) {

this.context = context;

}

public void onFabClicked(View view) {

user.name.set(“NAME”);

user.email.set(“EMAIL”);

}

}

Java Function Binding (Import)

Java functions can also be bound to UI components. If you want to do something with the value before displaying it on the UI, you can easily do so with the <import> tag.

public class BindingUtils {

public static String capitalize(String text) {

return text.toUpperCase();

}

}

To use this method in your layout, use the <import> tag to import the class, then call the method on the attribute.

<?xml version=”1.0" encoding=”utf-8"?>

<layout xmlns:android=”http://schemas.android.com/apk/res/android">

<data>

<import type=”info.latitudetechnolabs.databinding.BindingUtils” />

</data>

<LinearLayout …>

<TextView

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@{BindingUtils.capitalize(user.name)}” />

</LinearLayout>

</layout>

Explore How To Add Data Binding To Your Project

Data binding is a support library that works with Android 4.0 (API level 14) and higher devices. Here is the step by step procedure on how to add data binding in your project.

  1. In Your Module’s build.gradle File, Enable Data Binding

buildFeatures {

dataBinding true

}

  1. Make your Activity and Fragment as shown below

<?xml version=”1.0" encoding=”utf-8"?>

<layout>

<data>

<variable

name=”characterViewModel”

type=”com.example.databindingsample.ui.randomcharacter.CharacterViewModel” />

<import type=”android.view.View” />

</data>

<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.randomcharacter.CharacterFragment”>

<androidx.recyclerview.widget.RecyclerView

android:id=”@+id/rvCharacters”

android:layout_width=”match_parent”

android:layout_height=”0dp”

android:orientation=”vertical”

app:layoutManager=”androidx.recyclerview.widget.LinearLayoutManager”

app:layout_constraintBottom_toBottomOf=”parent”

app:layout_constraintEnd_toEndOf=”parent”

app:layout_constraintStart_toStartOf=”parent”

app:layout_constraintTop_toTopOf=”parent”

tools:itemCount=”6"

tools:listitem=”@layout/item_character” />

<ProgressBar

android:id=”@+id/pbCharactersLoading”

android:layout_width=”@dimen/dp_50"

android:layout_height=”@dimen/dp_50"

android:visibility=”@{characterViewModel.isLoading ? View.VISIBLE : View.GONE}”

app:layout_constraintBottom_toBottomOf=”parent”

app:layout_constraintEnd_toEndOf=”parent”

app:layout_constraintStart_toStartOf=”parent”

app:layout_constraintTop_toTopOf=”parent” />

<androidx.appcompat.widget.AppCompatTextView

android:id=”@+id/tvContentStatus”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:text=”@string/no_data_found”

android:textColor=”@color/black”

android:textSize=”@dimen/sp_15"

android:visibility=”@{characterViewModel.contentStatus &lt;= 0 ? View.VISIBLE : View.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>

Credit: fragment_character.xml hosted by GitHub

Bind your ViewModel to CharacterFragment at this point.

package com.example.databindingsample.ui.randomcharacter

import com.example.databindingsample.R

import com.example.databindingsample.common.extensions.safeObserve

import com.example.databindingsample.common.extensions.viewModel

import com.example.databindingsample.data.randomcharacter.entity.CharacterItem

import com.example.databindingsample.databinding.FragmentCharacterBinding

import com.example.databindingsample.domain.base.UiState

import com.example.databindingsample.ui.base.BaseViewModelFragment

import dagger.hilt.android.AndroidEntryPoint

import timber.log.Timber

import java.util.*

@AndroidEntryPoint

class CharacterFragment :

BaseViewModelFragment<CharacterViewModel, FragmentCharacterBinding>(R.layout.fragment_character) {

private val TAG = “CharacterFragment”

private val characterAdapter by lazy {

CharacterAdapter()

}

override fun buildViewModel(): CharacterViewModel = viewModel(viewModelFactory)

override fun getClassName(): String = “CharacterFragment”

override fun initViews() {

super.initViews()

setUpViewModel()

setUpRecyclerView()

viewModel.getCharacters(1)

}

private fun setUpViewModel() {

binding.characterViewModel = viewModel

binding.lifecycleOwner = this

}

private fun setUpRecyclerView() {

with(binding) {

rvCharacters.adapter = characterAdapter

}

}

override fun initLiveDataObservers() {

super.initLiveDataObservers()

with(viewModel) {

charactersLiveEvent.safeObserve(viewLifecycleOwner, ::handleCharacterResponse)

}

}

private fun handleCharacterResponse(uiState: UiState<ArrayList<CharacterItem>>) {

when (uiState) {

is UiState.Success -> {

characterAdapter.addAll(uiState.data)

}

is UiState.Error -> {

Timber.e(uiState.throwable)

}

}

}

}

CREDIT: CharacterFragment.kt hosted by GitHub

The item charcter.xml for the Recyclerview item can be found here.

<?xml version=”1.0" encoding=”utf-8"?>

<layout>

<data>

<variable

name=”character”

type=”com.example.databindingsample.data.randomcharacter.entity.CharacterItem” />

</data>

<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:id=”@+id/charItem”

android:layout_width=”match_parent”

android:layout_height=”wrap_content”

android:background=”?android:selectableItemBackground”

android:clickable=”true”

android:focusable=”true”

android:padding=”@dimen/dp_10">

<androidx.appcompat.widget.AppCompatImageView

android:id=”@+id/ivCharacterProfile”

android:layout_width=”@dimen/dp_100"

android:layout_height=”@dimen/dp_100"

android:scaleType=”centerCrop”

android:src=”@drawable/avatar”

app:layout_constraintStart_toStartOf=”parent”

app:layout_constraintTop_toTopOf=”parent”

app:profileImageUrl=”@{character.image}” />

<androidx.appcompat.widget.AppCompatTextView

android:id=”@+id/tvCharacterName”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_marginStart=”@dimen/dp_10"

android:text=”@{`Name : ` + character.name}”

android:textColor=”@color/black”

android:textSize=”@dimen/sp_20"

app:layout_constraintStart_toEndOf=”@id/ivCharacterProfile”

app:layout_constraintTop_toTopOf=”@id/ivCharacterProfile”

tools:text=”Devid” />

<androidx.appcompat.widget.AppCompatTextView

android:id=”@+id/tvGender”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_marginTop=”@dimen/dp_5"

android:text=”@{`Gender : ` + character.gender}”

android:textColor=”@color/black”

android:textSize=”@dimen/sp_20"

app:layout_constraintStart_toStartOf=”@id/tvCharacterName”

app:layout_constraintTop_toBottomOf=”@id/tvCharacterName”

tools:text=”Devid” />

<androidx.appcompat.widget.AppCompatTextView

android:id=”@+id/tvStatus”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_marginTop=”@dimen/dp_5"

android:text=”@{`Status : ` + character.status}”

android:textColor=”@color/black”

android:textSize=”@dimen/sp_20"

app:layout_constraintStart_toStartOf=”@id/tvCharacterName”

app:layout_constraintTop_toBottomOf=”@id/tvGender”

tools:text=”Devid” />

<androidx.appcompat.widget.AppCompatImageView

android:id=”@+id/ivStatus”

android:layout_width=”@dimen/dp_15"

android:layout_height=”@dimen/dp_15"

android:layout_marginStart=”@dimen/dp_10"

android:background=”@drawable/shape_status”

android:backgroundTint=”@{character.status.equalsIgnoreCase(`Alive`) ? @color/green : @color/red }”

android:elevation=”@dimen/dp_10"

app:layout_constraintBottom_toBottomOf=”@id/tvStatus”

app:layout_constraintStart_toEndOf=”@id/tvStatus”

app:layout_constraintTop_toTopOf=”@id/tvStatus” />

</androidx.constraintlayout.widget.ConstraintLayout>

</layout>

CREDIT: item_character.xml hosted by GitHub

Here <data> is used to bind UI with data

<variable> is used to add the name and type that you wish to add and bind to UI.

Binding Data to XML file

package com.example.databindingsample.ui.randomcharacter

import android.view.LayoutInflater

import android.view.ViewGroup

import com.example.databindingsample.data.randomcharacter.entity.CharacterItem

import com.example.databindingsample.databinding.ItemCharacterBinding

import com.example.databindingsample.ui.base.BaseRecyclerViewAdapter

import com.example.databindingsample.ui.base.BaseRecyclerViewHolder

class CharacterAdapter :

BaseRecyclerViewAdapter<CharacterItem, CharacterAdapter.CharacterViewHolder>() {

override fun createItemViewHolder(

parent: ViewGroup,

viewType: Int

): CharacterAdapter.CharacterViewHolder {

return CharacterViewHolder(

ItemCharacterBinding.inflate(

LayoutInflater.from(parent.context),

parent,

false

)

)

}

override fun bindItemViewHolder(holder: CharacterAdapter.CharacterViewHolder, position: Int) {

holder.bind(items[position])

}

inner class CharacterViewHolder(

private val itemCharacterBinding: ItemCharacterBinding

) : BaseRecyclerViewHolder<CharacterItem>(itemCharacterBinding.root) {

override fun bind(item: CharacterItem) {

with(itemCharacterBinding) {

character = item

}

}

}

}

Credit: CharacterAdapter.kt hosted by GitHub

Binding Adapter:

Binding Adapters are used to add custom setters to certain of your views’ properties. Setting an image to an ImageView, where the image is primarily loaded off the UI thread, is the most common use case I can think of.

package com.example.databindingsample.util

import androidx.appcompat.widget.AppCompatImageView

import androidx.databinding.BindingAdapter

import com.bumptech.glide.Glide

import com.example.databindingsample.R

object GlideUtils {

@JvmStatic

@BindingAdapter(“profileImageUrl”)

fun profileImageUrl(imageView: AppCompatImageView, url: String?) {

if (url?.isNotEmpty() == true) {

Glide.with(imageView.context)

.load(url)

.placeholder(R.drawable.avatar)

.into(imageView)

}

}

}

Credit: GlideUtils.kt hosted by GitHub

Final Words

By reading the whole article, you may now have enough information about android data binding. It may take a long for some and take very little time for some developers in android data binding. You can reach us at latitude technolabs for any support related to it. We have dedicated experts for android development.

--

--

Latitude Technolabs
Latitude Technolabs

Written by Latitude Technolabs

Latitude Technolabs Pvt. Ltd. is a leading service provider with extensive experience in providing IT outsourcing services to enterprises across the globe.

No responses yet