How to Create Android Universal Recycler View Adapter with MVVM And Data Binding
Hello friends, In android application development the most repetitive task is to setup recycler view, in this post, we will discuss how we can create a universal recycler view adapter for most of the cases with the help of MVVM and data binding.
Enable Data Binding
Add below code in app level build.gradle inside android{ }
dataBinding {
enabled = true
}
Add Dependencies
First dependency for MVVM components like ViewModel, etc.
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
Create a recycler view item (item_simple.xml)
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="model"
type="com.techpaliyal.androidkotlinmvvm.model.BasicModel" />
<variable
name="listener"
type="com.techpaliyal.androidkotlinmvvm.listeners.BasicListener" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:padding="5dp"
android:textSize="16sp"
android:text="@{model.name}"
android:onClick="@{()->listener.onClick(model)}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Note: data variable’s names should be model and listener for all item layouts use the Universal adapter
Code for the Universal Recycler View Adapter
class UniversalRecyclerAdapter<T>(
@LayoutRes val resource: Int, var data: ArrayList<T>,
val listener: Any? = null
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
fun updateData(data: ArrayList<T>){
this.data = data
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutInflator = LayoutInflater.from(parent.context)
val binding =
DataBindingUtil.inflate<ViewDataBinding>(layoutInflator, resource, parent, false)
return MyViewHolder(binding)
}
override fun getItemCount(): Int {
return data.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is UniversalRecyclerAdapter<*>.MyViewHolder) {
val item = data.get(position)
if (item != null)
holder.setupData(item)
}
}
inner class MyViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root) {
fun setupData(model: Any) {
binding.setVariable(BR.model, model)
binding.setVariable(BR.listener, listener)
}
}
}
the is used to define the model, it is a dynamic type.
BR is a directory file which maintains the variable reference of data binding, it is the same as R file in android.
In item_simple.xml the variable name should be model and listener so detected by Universal Recycler Adapter.
Create a binding adapter
@BindingAdapter(value = ["tools:data","tools:itemList", "tools:itemListener"], requireAll = false)
fun <T> setAdapter(recyclerView: RecyclerView, data : MutableLiveData<ArrayList<T>>, @LayoutRes listItem : Int = R.layout.item_simple, itemListener: Any){
if (recyclerView.adapter == null){
recyclerView.adapter = UniversalRecyclerAdapter(listItem, data.value ?: ArrayList(), itemListener)
}else{
if (recyclerView.adapter is UniversalRecyclerAdapter<*>) {
val items = data.value ?: ArrayList()
(recyclerView.adapter as UniversalRecyclerAdapter<T>).updateData(items)
}
}
}
note: This code is directly inside RecyclerViewExtension.kt
This above data binding function helps to set an adapter, data (array) and item layout directly from XML, so no need to do from code.
activity_basic_listing.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.techpaliyal.androidkotlinmvvm.ui.view_model.BasicListingActivityViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.activity.BasicListingActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:itemList="@{@layout/item_simple}"
tools:itemCount="5"
tools:data="@{viewModel.data}"
tools:itemListener="@{viewModel.basicListener}"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
here we use attributes
tools:itemList=”@{@layout/item_simple}”
tools:data=”@{viewModel.data}”
tools:itemListener=”@{viewModel.basicListener}”
which are declared in DataBinding function
Create BasicListingActivityViewModel
class BasicListingActivityViewModel(application: Application) : AndroidViewModel(application),
BasicListener<BasicModel> {
override fun onClick(model: BasicModel) {
Toast.makeText(getApplication(), model.name, Toast.LENGTH_LONG).show()
}
val data = MutableLiveData<ArrayList<BasicModel>>(ArrayList<BasicModel>())
val basicListener : BasicListener<BasicModel> ?= this
fun setData(){
val tempArr = ArrayList<BasicModel>()
tempArr.add(BasicModel(name = "Yogesh"))
tempArr.add(BasicModel(name = "Umesh"))
tempArr.add(BasicModel(name = "Sohan"))
tempArr.add(BasicModel(name = "Madan"))
data.value = tempArr
}
}
ViewModel is a class that is responsible for preparing and managing the data for an Activity or a Fragment.
In this ViewModel, we took 2 variables data and basicListener (to listen from recycler item)
Connect the view model with BasicListingActivity
class BasicListingActivity : AppCompatActivity(){
lateinit var binding: ActivityBasicListingBinding
companion object{
fun start(context: Context){
val intent = Intent(context, BasicListingActivity::class.java)
context.startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_basic_listing)
binding.lifecycleOwner = this
val viewModel = ViewModelProviders.of(this).get(BasicListingActivityViewModel::class.java)
binding.viewModel = viewModel
binding.executePendingBindings()
binding.viewModel?.setData()
}
}
Now run our application.
Output :
Any design can be achieved using this here is a some sample
You can check full code on Github
If found any bug or having suggestions, please comment below.
The post How to Create Android Universal Recycler View Adapter with MVVM And Data Binding appeared first on TechPaliyal.