Trying to make one adapter fit all RecyclerViews in the application.
While this is not an absolute use-case as we might want different list to behave differently. But the core purpose of RecyclerView is to display the data and be able to scroll through it. Also, when we click on the list-item we possible want to navigate to details for that list-item. While doing this, there will be a lot of redundant code that will be duplicated in all RecyclerView adapters in our codebase.
Below is a basic example of abstracting away the core functionality of a RecyclerView adapter and have the sub-classes take care of the rest. This articles assumes that the readers will have basic understanding of RecyclerView
, databinding
and kotlin
.
abstract class BaseRecyclerViewAdapter<T> : Adapter<ViewHolder>(), {
var items: List<T> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = getViewHolder(parent, viewType)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if(position in items.indices) {
(holder as Binder<T>).bind(items[position])
}
abstract fun getViewHolder(parent: ViewGroup, viewType: Int): ViewHolder
interface Binder<in T> {
fun bind(item: T)
}
}
Usage
The above abstract RecyclerView adapter can be used in a fragment as follows:
class SomeListFragment {
private lateinit var adapter: SomeAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) : View? {
super.onCreateView(inflater, container, savedInstanceState)
// initialization code here ...
adapter = SomeAdapter() // initialize adapter here
// ...
}
// rest of fragment implementation
inner class SomeAdapter : BaseRecyclerViewAdapter<SomeData>() {
override fun getViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val viewBinding: SomeListItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.some_list_item, parent, false)
return SomeViewHolder(viewBinding)
}
}
inner class SomeViewHolder(private val viewBinding: SomeListItemBinding) : ViewHolder(viewBinding.root), BaseRecyclerViewAdapter.Binder<SomeData> {
override fun bind(item: SomeData) {
/*
bind data here, we can also assign click listeners
viewBinding.root.setOnClickListener { ... }
*/
}
}
}
Please provide feedback in comments.
Thank you for reading.
Top comments (3)
Or you can use listadapter and abstract over it, it offers diff utils with nice animations.
@crazylegend Thank you for the feedback. I will try to put something together for
ListAdapter
in my future post.That is correct. We don't need to override that in the above use case.
I will update the post. Thanks @Stavro Xhardha