
Improving Android DataBinding with Bindables library
DataBinding is one of the most important factors for MVVM architecture. The basic concept of DataBinding is to link the view and view model via observer patterns, properties, event callbacks, etc. Linking and automating communication between the view via the bound properties or something in the view model has a lot of benefits in the MVVM architecture concept.

The main purpose of the DataBinding is that helps data interaction between the view and view model, and notifies data changes to view from view model via bound properties. The view then does not need to post-process the data it receives from the domain layer, only draws UI items on the screen. It can take some advantages from this kind of structure because we can focus only on UI/UX things or domain-related logic separately when we need to add new features. Also, we can get advantages of the maintenance perspective. Here is a simple example from the Pokedex.
The MainActivity has a grid list to show the Pokemons and we need to fetch data from the network or integrate them into the database. And we should show a detailed screen when users touch a list item. As we can see from the above codes, it’s quite simple because it uses DataBinding. If we want to change the data model or the design for fetching data or integrating with the database or whatever, we don’t have to change any codes in the MainActivity.
Bindables
So we can take some advantages from DataBinding. For improving the DataBinding usages and reducing the many kinds of boilerplates that we must be required to construct DataBinding designs in the Android project, I’ve been published a library called Bindables that helps lots of DataBinding related constructions in initial projects.
BindingActivity
Through various project experiences, I felt we wrote a lot of repeated codes for inflating DataBinding layouts in our Activity, Fragment, DialogFragment or etc. Generally, we should initialize DataBinding related codes like the below.
The most repeated codes that I’ve thought of are declaring the global property, setting contentView via DataBindingUtil, and we have to use a scope expression for initializing DataBinding variables like apply
, with
, or etc in every activity and fragment. So Bindables
introduces BindingActivity
, BindingFragment
, BindingDialogFragment
, BindingBottomSheetDialogFragment
for reducing initialization of the DataBinding boilerplates. We can see the basic usages of these classes.
BindingActivity
is a base class for Activities that wish to bind content layout with DataBindingUtil
. It provides a binding
property that extends ViewDataBinding
from abstract information. The binding
property will be initialized lazily and ensures to be initialized before being called super.onCreate
in Activities. So we don't need to inflate layouts, setContentView, and initialize a binding property manually. Also, we can use binding
scope expression to execute a block of code within the context of the binding instance.
Extending Binding classes
Sometimes we need to implement our custom base classes. In this case, we can extend binding classes like the below for designing your own base class.
LiveData in ViewModel
Generally, we use LiveData
for notifying ViewModel to UI layers and holding it. But for the reason the value of the MutableLivedata
can be modified and exposed from the outside, we should create backing properties for preventing value changes from outsides.
But this kind of implementation does not looking good, also we should create two properties for delivering one data model. It’s quite a wasteful implementation, and some developers design interfaces or abstract ViewModels for overriding and reducing this kind of backing properties. But that also requires writing more codes than we need.
BindingViewModel
BindingViewModel
provides a way in which UI can be notified of changes by the ViewModel without the LiveData
, ObservableField
, or etc. Using bindingProperty
, we can notify specific data changes and it can be observed in UI layers. We can make all types of properties being observable from the UI layers using bindingProperty
and Bindable
annotation. Also, we can prevent modifying the value of the property from outsides.
In our XML files, the changes of properties value will be notified to the DataBinding layer automatically whenever the value changes.
notifyPropertyChanged
we can customize setters of general properties for notifying data changes to UI layers using @get:Bindable
annotation and notifyPropertyChanged()
in the BindingViewModel
. Also, we can notify data changes whenever we want using the notifyPropertyChanged()
.
Two-way binding
We can implement two-way binding properties using the bindingProperty
. Here is a representative example of the two-way binding using TextView
and EditText
.
Here is an XML layout. The text will be changed whenever the viewModel.editText
is changed.
In your Activity or Fragment, we can set the viewModel.editText
value whenever the EditText
's input is changed. We can implement this another way using inversebindingadapter
.
Binding functions
We can also implement bindable functions using @Bindable
annotation and notifyPropertyChanged()
in the BindingViewModel
. And the @Bindable
annotated method's name must start with get
.
Whenever we call notifyPropertyChanged(::getFetchedData)
, getFetchedString()
will be called and the UI layer will get the updated data.
android:text="@{viewModel.fetchedData}"
Binding Flow
We can create a binding property from Flow
using @get:Bindable
and asBindingProperty
. UI layers will get newly collected data from the Flow
or StateFlow
on the viewModelScope
or we can set a coroutine scope. And the property by the Flow
must be read-only (val), because its value will be changed only by collecting data of the Flow
.
As we can see from the above codes, the pokemonInfo
property collects data from the pokemonInfoFlow
that initialized by the repository. The read-only property pokemonInfoFlow
will collect data and it can be observed in the UI layers. We can see more details in the Pokedex.
Binding SavedStateHandle
We can create a binding property from SavedStateHandle
in the BindingViewModel
using @get:Bindable
and asBindingProperty(key: String)
. UI layers will get newly saved data from the SavedStateHandle
and we can set the value into the SavedStateHandle
when we just set a value to the property.
BindingRecyclerViewAdapter
We can create binding properties in the RecyclerView.Adapter
using the BindingRecyclerViewAdapter
. In the below example, the isEmpty
property is observable in the XML layout. And we can notify value changes to DataBinding using notifyPropertyChanged
.
In the below example, we can make the placeholder
being gone when the adapter's item list is empty or loading data.
BindingModel
We can use binding properties in our own classes by extending the BindingModel
and those properties are observable in UI layers.
Conclusion
In this posting, we looked around how to improve usages of DataBinding using the Bindables library. DataBinding reduces many kinds of codes in activities and fragments for post-processing and applying the data model to the UI components. Also, it allows us to correspond flexibly from the domain logic changes, structures, or etc. So If you are considering using DataBinding in your new project, or if you are already using DataBinding but want to changes to better usages, hope you try to use Bindables. 😄