Generic adapter with kotlin part-I

Mohan G
2 min readDec 13, 2017

--

In android its very common to show the data in list . Usually we do that using ListView or RecyclerView.

If a project has 10 different lists with ten different items then usually people end up in creating 10 different adapter. Lets solve this problem by creating single adapter but writing 10 different view holders for it.

As shown in above snippet lets inflate a view inside onCreateViewHolder() function using the viewType passed to it.

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return getViewHolder(LayoutInflater.from(parent.context)
.inflate(viewType, parent, false)
, viewType)
}

getViewHolder() is a abstract function which returns Recyclerview.ViewHolder ,which will be implemented by the user while creating the adapter.

abstract fun   getViewHolder(view:View,viewType:Int):RecyclerView.ViewHolder

Inside onCreateViewHolder() as we are using viewType to inflate view , we need to override getViewType() function of RecyclerView.Adapter .

override fun getItemViewType(position: Int): Int {
return getLayoutId(position, listItems[position])
}

Again getLayoutId is a abstract function which will be implemented by user while creating a adapter instance .

protected abstract fun getLayoutId(position: Int, obj: T): Int

Thats it , we have created a generic adapter lets use it and see how it works.

val myAdapter = object : GenericAdapter<String>(listOf("RED","YELLOW","ORANGE")) {
override fun getLayoutId(position: Int, obj: String): Int {
return R.layout.car_layout
}

override fun getViewHolder(view: View, viewType: Int): RecyclerView.ViewHolder {
return MyViewHolder(view)
}
}
recyclerView.layoutManager=LinearLayoutManager(this)
recyclerView.setHasFixedSize(true)
recyclerView.adapter=myAdapter

we gave implementation for two abstract function getLayoutId and getViewHolder . In our case we returned a layout which we want to inflate and ViewHolder which we want to bind views.

class MyViewHolder : RecyclerView.ViewHolder, GenericAdapter.Binder<Car> {

var textView: TextView
constructor( itemView: View):super(itemView){
textView = itemView.findViewById(R.id.carName)
}
override fun bind(s: Car) {
textView.text = s.name
}
}

Now lets create a viewHolder which extends RecyclerView.ViewHolder and implements Binder interface which we created earlier inside GenericAdapter class

internal interface Binder<T> {
fun bind(data: T)
}

Binder is a interface which has bind function . Our viewHolder will implement this so that we can bind data with views. Don’t forget to implement this interface with your ViewHolder otherwise you will end up in getting class cast exception.

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as Binder<T>).bind(listItems[position])
}

Since our viewholder implements Binder interface , we can type cast holder as Binder and bind our data with the views.

The beauty of this adapter is you can create multiviewType list very easily.

val myAdapter = object : GenericAdapter<Any>(listOf(Car("Audi",Color.BLACK),Bus("Benz",Color.WHITE))) {
override fun getLayoutId(position: Int, obj: Any): Int {
return when(obj){
is Car->R.layout.car_layout
is Bus->R.layout.bus_layout
else->R.layout.car_layout
}
}

override fun getViewHolder(view: View, viewType: Int): RecyclerView.ViewHolder {

return when(viewType){

R.layout.car_layout->CarViewHolder(view)
R.layout.bus_layout->BusViewHolder(view)
else->BusViewHolder(view)
}
}
}

Consider the example above your list has different objects , based on the object type we return different layouts and based on different layout we return different ViewHolders.

Find the working code here

Thats it folks , will cover some more details in next blog.

--

--