Android Data Binding and RecyclerView

Data binding library in Android provides useful utilities which help us in many ways. Binding the source of the TextView to a string field is as easy as

android:text=”@{viewModel.name}”

However let’s say in our view model we also want to fetch a list of items from a web API and display it in a RecycerView. There are many articles suggesting how to use data binding with RecyclerView, and the basic idea is to hold a reference to the ViewDataBinding object in the ViewHolder and to initialize the variables in onBindViewHolder like this.

@Override
public void onBindViewHolder(BindingHolder<VDB> holder, int position) {
holder.getBinding().setViewModel(viewModelList.get(position));
}

Applying this approach I have come up with a more generic solution to have a default implementation for RecyclerView.Adapter.

First add the library to your project

compile 'com.samvel1024.databindingrv:data-binding-recyclerview:0.0.3'

The view model which is responsible for fetching the list items has to provide a list of child view models each of which is going to be bound to the recycler view item.

public class MainViewModel extends BaseObservable {

private List<ListItemViewModel> viewModels;

public MainViewModel() {
viewModels = new ArrayList<>(Arrays.asList(
new ListItemViewModel("Toyota Camry", "34000$"),
new ListItemViewModel("Honda Civic", "32000$"),
new ListItemViewModel("BMW M3", "85000$"),
new ListItemViewModel("Volkswagen Golf", "40000$")
));
}

@Bindable
public List<ListItemViewModel> getItemViewModels() {
return viewModels;
}

public void onAddItemClicked() {
viewModels.add(new ListItemViewModel("A new car", "80000$"));
notifyPropertyChanged(BR.itemViewModels);
}

}

Just as any other bindable view you can update the list just by calling notifyPropertyChanged()

The xml is as simple as

<com.samvel1024.databindingrv.BindingRecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:bindingVarPath="com.example.myapp.BR.viewModel"
app:itemLayoutResId="@layout/list_item"
app:layoutManager="LinearLayoutManager"
app:viewModelList="@{viewModel.itemViewModels}" />

The important attribute here is bindingVarPath which is the full BR class name appended with name of the list item’s variable. And finally the list item xml.

<layout>

<data>

<variable
name="viewModel"
type="com.example.myapp.ListItemViewModel" />
</data>

<LinearLayout ...>

<TextView
...
android:text="@{viewModel.name}" />

<TextView
...
android:text="@{viewModel.price}" />

<Button
...
android:onClick="@{() -> viewModel.onBuyButtonClicked()}"/>

</LinearLayout>
</layout>

The approach provided cuts down redundant code for defining the adapter and calling notifyDatSetChanged() every time you update the list. However, the drawback is that it is not yet much flexible and it is usable only for fairly simple recycler views.

You can view the full source code and the documentation in https://github.com/samvel1024/databinding-recyclerview