As an Android developer, you’ll be familiar with ViewHolder after using ListView or RecycleView. ViewHolder was not originally provided by Android, but was introduced in ListView as a way to reduce frequent calls to findViewById, and then built directly into the RecycleView. However, we cannot escape the fate of writing ViewHolder or findViewById when writing the adapter.

Now Kotlin seems to solve the problem easily. You may remember that with the introduction of Kotlin, views can be used directly in an Activity using the Id of the layout file. Check out the previous article on how Kotlin uses the control Id directly. This article uses this feature to encapsulate a simple universal RecycleView adapter that does not need to create a ViewHolder.

General ViewHolder

First of all, Kotlin’s above features are disabled by default in normal View. Open the app build.gradle and enable experimental features:

android {
...
}

androidExtensions {
    experimental = true
}
Copy the code

Then create a generic ViewHolder, which is as simple as one line:

   class CommonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), LayoutContainer {

        override val containerView: View = itemView
    }
Copy the code

Minimalist adapter

Let’s go straight to the code:

open class BaseRecyclerAdapter<M>(
    @LayoutRes val itemLayoutId: Int, list: Collection<M>? = null,
    bind: (BaseRecyclerAdapter<M>.() -> Unit)? = null
) :
    RecyclerView.Adapter<BaseRecyclerAdapter.CommonViewHolder>() {

    init {
        if(bind ! =null) {
            apply(bind)
        }
    }

    private var dataList = mutableListOf<M>()

    private var mOnItemClickListener: ((v: View, position: Int) - >Unit)? = null
    private var mOnItemLongClickListener: ((v: View, position: Int) - >Boolean) = {_, _ ->false }

    private var onBindViewHolder: ((holder: CommonViewHolder, position: Int) - >Unit)? = null

    fun onBindViewHolder(onBindViewHolder: ((holder: CommonViewHolder, position: Int) -> Unit)) {
        this.onBindViewHolder = onBindViewHolder
    }

    /** * populates the data, which clears the original data **@paramList Data to fill *@returnTrue: Populates successfully and calls refresh data */
    fun setData(list: Collection<M>?: Boolean {
        var result = false
        dataList.clear()
        if(list ! =null) {
            result = dataList.addAll(list)
        }
        return result
    }

    /** * Get a data from position **@paramPosition View position *@returnData * /
    fun getItem(position: Int) = dataList[position]

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommonViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(itemLayoutId, parent, false)
        valviewHolder = CommonViewHolder(itemView) itemView.setOnClickListener { mOnItemClickListener? .invoke(it, viewHolder.adapterPosition) } itemView.setOnLongClickListener {return@setOnLongClickListener mOnItemLongClickListener.invoke(it, viewHolder.adapterPosition) }
        return viewHolder
    }

    override fun getItemCount(a) = dataList.size

    override fun onBindViewHolder(holder: CommonViewHolder, position: Int) {
        if(onBindViewHolder ! =null) { onBindViewHolder!! .invoke(holder, position) }else {
            bindData(holder, position)
        }
    }

    open fun bindData(holder: CommonViewHolder, position: Int){}class CommonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), LayoutContainer {

        override val containerView: View = itemView
    }

}
Copy the code

use

Start by creating a simple layout for item_textview.xml:

<? xml version="1.0" encoding="utf-8"? > <TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/textview"
          android:layout_width="match_parent"
          android:layout_height="50dp">

</TextView>
Copy the code

We can create it by inheriting the adapter:

class StringAdapter : BaseRecyclerAdapter<String>(R.layout.item_textview) {

    override fun onBindViewHolder(holder: CommonViewHolder, position: Int) {
        super.onBindViewHolder(holder, position)
        holder.textview.text = getItem(position)
    }
}
Copy the code

It can also be created directly as a DSL:

   val adapter = BaseRecyclerAdapter<String>(R.layout.item_textview) {
        onBindViewHolder { holder, position ->
            holder.textview.text = getItem(position)
        }
    }
Copy the code