Preface
Before going to details, I will give you a brief summary of what on earth this post is about so that you can skip it if you had something similar. In Android development, we usually use a RecyclerView to represent a list of items. Coming with the list are an adapter and one to many view holders. Therefore, whenever you want to show a list, you need to create a bunch of classes. Here I created a common adapter and view holder that, together with data binding, can be used for any data set. This means that you only have to create these classes once and reuse them multiple times.
Prerequisite
This post assumed that you’re familiar with Android and it’s data binding feature. If you’re new to the concept, check out the official documents.
Implementation
DataBindingEntry
First, we need to provide necessary binding information so that the adapter knows what and how to display. That’s the idea of the DataBindingEntry class:
This class contains the item’s layout id and a map of binding variables to their corresponding data in that layout.
DataBindingViewHolder
As the name infers, DataBindingViewHolder will do the binding “ritual” between view and data. This is the most important part of the whole approach, where everything can be abstract thanks to the power of data binding.
ViewDataBinding is the base class that every binding class generated by Android extends from. The reason why we don’t need a concrete implementation is because the base class has a method called setVariable that accepts any object. For concrete classes, you will have extra setters for variables you have declared in the layouts. When onBindViewHolder method in the adapter is called, a DataBindingEntry at a specific position will be passed in the holder’s bind method. Here we use the setVariable mentioned previously to bind all variables provided by the entry.
The last important piece in the holder is extending the LifecycleOwner interface. If you want to use LiveData in your project, you have to setup the lifecycleOwner property of the ViewDataBinding instance. For that, I made the class a LifecycleOwner and created onAppear and onDisappear methods to update the life cycle state according to the view’s visibility. As a result, the data will only emit update when the list item is visible on screen.
DataBindingAdapter
This class is the last piece of the puzzle, where all the things are wired up. The adapter will be responsible to create and bind the view holders as well as get the appropriate layout for the items.
Notice that onViewAttachedToWindow and onViewDetachedFromWindow methods within the adapter. Basically, they are called when a view holder becomes either visible or hidden. Thus, it’s a perfect place to invoke the DataBindingViewHolder’s life cycle functions.
That’s it! That’s all you need to construct a binding list that can be utilized for any data set, even a complex one. The only work left is doing the binding in the layouts properly. Furthermore, I also wrote some binding utilities to minimize the boilerplate code, which is going to be shown in the next section.
Binding Adapters & RecyclerViewModel
Thanks to data binding, we are able to write custom setters which can be used in the layouts. Hence, let’s try to setup the RecyclerView automatically with just one simple attribute.
RecyclerViewModel contains everything we need to initialize the RecyclerView, including the data binding entries along with the LayoutManager and ItemDecoration (if there is any). Then, after defining model attribute with the help of BindingAdapter, we put it into the layout as below:
Conclusion
I know that there are some libraries that have already done the same thing or had something similar. However, this was a good way, at least for me, to hone my skills and I learned a lot while implementing this. Anyway, if you’re already familiar with data binding and don’t have time to learn another library, this may be a good solution.
Here is a sample code that is using the implementation above. Check it out if you like Pokemon :D!
