Powerful and Reusable ListAdapter Using DataBinding for Simple Lists


Through the years of developing Android apps, there have been countless times that we implemented simple lists. Lists that only have these basic features:

  1. Display items
  2. Handle item clicks

Using ListAdapter and with the help of DataBinding, we can create a powerful and reusable SimpleListAdapter which we can use every time we implement a simple list.

I’ll share a step by step tutorial in this article on how to achieve this.

Enough of the introduction and let’s get our hands dirty!

1. Let’s create our item layout. For this one, let’s assume we will display a list of news articles. Let’s go ahead and create our layout called item_article.xml.

...<data>
    <variable
        name="item"
        type="com.your.package.name.Article" />
</data>...<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/itemClickable"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?attr/selectableItemBackground"
    android:clickable="true"
    android:focusable="true"
    android:padding="13dp">    

... Your layout implementation.
</androidx.constraintlayout.widget.ConstraintLayout>

There are 2 things to note here:

  • First, your item layout’s variable must be named item.
  • Second, the view that handles the item click should have an id of itemClickable.

We will need them for the reusability of our adapter.

2. Let’s create our reusable ViewHolder class. We’ll simply name it ViewHolder.

open class ViewHolder<B : ViewDataBinding>(val binding: B) : RecyclerView.ViewHolder(binding.root) {
    fun bind(item: Any) {
        binding.setVariable(BR.item, item)
        binding.executePendingBindings()
    }
}

Notice that the variable item that we required in step 1 is being used here as BR.item.

Let’s just leave it like this. The parameters of this class will be explained in the later steps.

3. Let’s create our reusable adapter called SimpleListAdapter.

class SimpleListAdapter<T : Any, B : ViewDataBinding>(
    diffUtil: DiffUtil.ItemCallback<T>,
    @LayoutRes private val layoutId: Int,
    private val itemClickListener: (T) -> Unit
) : ListAdapter<T, ViewHolder<B>>(diffUtil) {
 
   // Will be implemented in the next steps...}

Let’s determine the parameters for this class. Note that this class accepts 2 type parameters and 3 constructor parameters. Let’s break them down below.

Dominate the App Store.

Get the latest industry news first.

Type parameters:

  • T : Any — This is the item type class. In our example, we should pass the class Article as the first type parameter.
  • B : ViewDataBinding — This is the item type binding class that has been generated by DataBinding from our item layout xml. Based on our example in step 1, the generated class should be ItemArticleBinding.

Constructor parameters:

  • diffUtil — You should implement a DiffUtil.ItemCallback unique for your item type. This will be used by the ListAdapter to validate your list items. We will be using ArticleDiffUtil in our example.
  • layoutId — This is the layout id of your item layout xml, which is R.layout.item_article in our example.
  • itemClickListener — Lastly, a callback that will be invoked every time user clicks an item from the list.

4. Let’s implement onCreateViewHolder method inside our SimpleListAdapter.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder<B> {
    return ViewHolder<B>(
        DataBindingUtil.inflate(
            LayoutInflater.from(parent.context),
            layoutId,
            parent,
            false
        )
    ).apply {
        binding
            .root
            .findViewById<View>(R.id.itemClickable)
            .setOnClickListener {
                itemClickListener.invoke(getItem(adapterPosition))
            }
    }
}

There are a few notable lines in this method:

  • layoutId passed to our constructor parameter is being used to inflate the binding class and pass it to our ViewHolder’s constructor.
  • itemClickListener passed to our constructor parameter is being invoked when an item click event occurs.
  • The required id from step 1, itemClickable, is being used as a subject for setting view click listener.

5. Let’s implement onBindViewHolder inside our SimpleListAdapter.

 

override fun onBindViewHolder(holder: ViewHolder<B>, position: Int) {
    holder.bind(getItem(position))
}

 

6. Finally, let’s use our SimpleListAdapter inside our activity/fragment.

binding.recyclerView.apply {
    adapter = 
        SimpleListAdapter<Article, ItemArticleBinding>(
            ArticleDiffUtil(),
            R.layout.item_article
        ) { item -> 
            // Handle item click...
        }
}

And that is basically it! We have just created our powerful and reusable SimpleListAdapter.

This is really handy in implementing simple lists. As long as your list only has 1 item click listener, you can reuse this adapter.

Bonus

I have created a gist for the reusable SimpleListAdapter. Feel free to use this in your projects!
Link: https://gist.github.com/jermainedilao/f7002e41f53bd601a3edd1437f498254

Dominate the App Store.

Get the latest industry news first.



Source link

Leave a Reply