My Solution to Challenge: RecyclerView ViewTypes

This a solution to the RecyclerView ViewTypes Challenge in Chapter 9. Its not so good but its something. I used a Base ViewHolder so that I can use multiple ViewHolders in my adapter.

// This is a data class that will hold the list data for the crimes
data class Crime(val id: UUID = UUID.randomUUID(), var requiresPolice: Int = 2 ,var title : String = “”, var date: Date = Date(), var isSolved: Boolean = false,
var contactPolice: String = “Contact Police”)

CrimeListFragment

My Base ViewHolder, normal and serious crimeViewHolder

// A Generic ViewHolder to be implemented by other ViewHolders
abstract class BaseViewHolder<T>(itemView: View) :
RecyclerView.ViewHolder(itemView) {

    abstract fun bind(crime: Crime)

}


// A ViewHolder in a RecyclerView makes reference to a view by their "itemViews" or storing them in a property called itemView
/** || FIRST VIEW HOLDER || **/
private inner class CrimeHolder(view: View)
    : BaseViewHolder<Crime>(view), View.OnClickListener {

    private lateinit var crime : Crime

    private val titleTextView : TextView = itemView.findViewById(R.id.crime_title)
    private val dateTextView : TextView = itemView.findViewById(R.id.crime_date)


    // We set an onClickListener on each crime represented by their itemViews
    // The itemView is the view for the entire row
    init {
        itemView.setOnClickListener(this)
    }



    // This function is added here so that our ViewHolder will do the binding work of the crimes instead of our TextViews(it is a good practice)
    override fun bind(crime: Crime) {
        this.crime = crime
        titleTextView.text = this.crime.title
        dateTextView.text = this.crime.date.toString()
    }


    // Since our ViewHolder implements the OnCLickListener itself, we need to implements its members,
    // In this case, we need to set what will happen when our button is clicked
    override fun onClick(v: View) {
        Toast.makeText(context, "${crime.title} pressed!", Toast.LENGTH_SHORT).show()
    }

}


// Second ViewHolder for our serious crime
/** || SECOND VIEW HOLDER || **/
private inner class SecondViewHolder(view :View)
    : BaseViewHolder<Crime>(view)  {

        private val buttonTextView : Button = itemView.findViewById(R.id.contact_police_button)


    override fun bind(crime: Crime) {


        buttonTextView.apply {
            text = crime.contactPolice
        }
    }
}

My ViewHolder Adapter

// A recyclerView does not create or hold ViewHolders by itself, rather it asks an "Adapter" to do so
// This class here sets the data the Recycler view will display through the CrimeHolder
private inner class CrimeAdapter(var crimes: List<Crime>)
    : RecyclerView.Adapter<BaseViewHolder<*>>() {


    val firstViewType = 0
    val secondViewType = 1



    // This wraps up the inflated recyclerView layout and passes to the CrimeHolder creating a new ViewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {

        return if (viewType == firstViewType) {
            return CrimeHolder(
                layoutInflater.inflate(R.layout.list_item_crime, parent, false)
            )
        } else {
            SecondViewHolder(
                layoutInflater.inflate(R.layout.serious_crime_layout, parent, false)
            )
        }



    }

    override fun getItemCount() = crimes.size   // This reveals the number of items in the list of crimes


    // Retrieves a viewType
    override fun getItemViewType(position: Int): Int {
        val crime = crimes[position]
        return crime.requiresPolice

    }


    // This obtains crimes from a particular position from the crime list and passes it to the CrimeHolder
    override fun onBindViewHolder(holder: BaseViewHolder<*>, position: Int) {
        val crime = crimes[position]
        holder.bind(crime)
    }


}

This is it. if any Improvements please let me know