Data Binding Adapters And Dependency Injection- A Short Love Story

Abdul Hakeem Mahmood
ProAndroidDev
Published in
4 min readMar 5, 2021

--

Data Binding and Dependency Injection are very hot topics for Android developers in the software industry nowadays. They once were a plus point in job descriptions but are now a mandatory skill requirement (rightly so).

Data Binding allows you to bind UI components in your layouts to data sources in your app using a declarative format rather than programmatically. In this sense, All views should be manipulated inside the XML layout file instead of the activity/fragment class.

This will not just wipe out redundant setViews out of the activity/fragment classes but also using Data Binding’s BindingAdapters you can create custom attributes for your UI component and reuse them everywhere in your project.

Basic Data Binding and Dependency Injection with Hilt is a pre-requisite as this article will not focus on the basics.

The goal of this article is to illustrate how can we gel Data Binding with Dependency Injection using Hilt-Android 🎯

The most simple and typical way of using Data Binding’s BindingAdapters which we all have been using or at-least have had used in the past is by static methods.

A typical example of a BindingAdapter would-be to load an image via the network. Rather than loading an image each time with Glide inside your fragment or activity, you can simply create a custom attribute with BindingAdapter and reuse it everywhere required.

First, you enable databinding in your app-level build.gradle and create a static or extension function and annotate it with @BindingAdapter(value = ["imageUrl"]) , anything that goes inside annotation parenthesis will be the name of your custom attribute which then you will be using in view XML.

Example:

TADAAA!! Our very first Binding Adapter is ready to be used.

But most of the time, the simple way is not the right way.

How nice it would be if we could make these static functions non-static? Converting them to non-static function won’t just make it easier to unit test them but also makes it possible to inject dependencies wherever and whenever required using hilt-android.

Converting static BindingAdapters to non-static functions is quite simple, using those non-static BindingAdapters is also not very hard, but using them with Hilt is a bit tricky. But not to worry, I gotcha.😉

Enough talking, let's get into some coding.

First, let’s wrap the static BindingAdapters inside a class to make them non-static. Once they are instance function bound to a class, we can use constructor injection on the class and obtain any dependency required.

Now since our functions are non-static, accessing each custom attribute throws a FATAL Exception.

The exception is very self-explanatory. It says that DataBinding requires a DataBindingComponent if not using static BindingAdapter functions.

DataBindingComponent: This interface is generated during compilation to contain getters for all used instance BindingAdapters. When a BindingAdapter is an instance method, an instance of the class implementing the method must be instantiated.

Let’s look at what’s inside at our DataBindingComponent

hmm!

So DataBindingComponent created an abstract function with our class as return type which contains the BindingAdapters.

Documentation also says, If using Dagger 2 (Hilt is just a wrapper over Dagger 2), the developer should extend this interface and annotate the extended interface as a Component.

Ahh! Documentation can be so helpful (sometimes 😝).

Let’s create a custom Hilt component

Four things that we need to create a custom component , a scope, a component, a component builder and an entry point.

Relax! Take a deep breath… we are pretty much done.

Now we need to make sure these BindingAdapters are provided to DataBinding , so that we can to use them inside the layout files.

To do so, we set a default component to DataBinding which expects a DataBindingComponent. Since our custom hiltcomponent (BindingComponent ) implements DataBindingComponent , we can provide it to the DataBinding with setDefaultComponent function from DataBindingUtil.

That's it! 👐

The sample project with the complete implementation can be found on GitHub.

Did I get something wrong? Mention it in the comments. I would love to improve. 😊

Did you learn anything? Was it helpful? If yes, leave some claps 👏. It will make me happy 😊

--

--