Search code examples
androidxmlkotlinandroid-recyclerviewexpandablerecyclerview

Incorrect position code when trying to implement RecyclerView click listener


I've spent quite a while trying to find the cause of this problem. I have a RecyclerView with several different view types but the problem I have is with the click event in 1 of my view holders (ViewHolderA). Since I get these errors, I don't know what else I should using instead. I think my item class may be the problem but I'm not sure where I've gone wrong.

'getter for position: Int' is deprecated in Java

Activity class

class MainActivity : AppCompatActivity() {
    private var mList: RecyclerView? = null
    private var mRecyclerAdapter: MyAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mList = findViewById(R.id.listRV)

        val listEntities = arrayListOf<Any>()
        listEntities.add(ItemA("A1", "A2"))
        listEntities.add(ItemB("B1"))
        listEntities.add(ItemC("C1", "C2", "C3", "C4"))
        listEntities.add(ItemD("D1", "D2", "D3", "D4"))

        val layoutManager = LinearLayoutManager(this)
        mList!!.layoutManager = layoutManager
        mRecyclerAdapter = MyAdapter(listEntities)
        mList!!.adapter = mRecyclerAdapter
    }
}

Adapter class

class MyAdapter(var mData: List<Any>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    private val typeA: Int = 1
    private val typeB: Int = 2
    private val typeC: Int = 3
    private val typeD: Int = 4

    override fun getItemViewType(position: Int): Int {
        return when {
            mData[position] is ViewHolderA -> {
                typeA
            }
            mData[position] is ViewHolderB -> {
                typeB
            }
            mData[position] is ViewHolderC -> {
                typeC
            }
            mData[position] is ViewHolderD -> {
                typeD
            }
            else -> -1
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        var layout = 0
        val viewHolder: RecyclerView.ViewHolder?
        when (viewType) {
            typeA -> {
                layout = R.layout.rv_item_a
                val viewA = LayoutInflater.from(parent.context).inflate(layout, parent, false)
                viewHolder = ViewHolderA(viewA)
            }
            typeB -> {
                layout = R.layout.rv_item_b
                val viewB = LayoutInflater.from(parent.context).inflate(layout, parent, false)
                viewHolder = ViewHolderB(viewB)
            }
            typeC -> {
                layout = R.layout.rv_item_c
                val viewC = LayoutInflater.from(parent.context).inflate(layout, parent, false)
                viewHolder = ViewHolderC(viewC)
            }
            typeD -> {
                layout = R.layout.rv_item_d
                val viewD = LayoutInflater.from(parent.context).inflate(layout, parent, false)
                viewHolder = ViewHolderD(viewD)
            }
            else -> viewHolder = null
        }
        return viewHolder!!
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (holder.itemViewType) {
            typeA -> {
                val detailsA = mData[position] as ItemA
                (holder as ViewHolderA).showDetails(detailsA)


                val mClickListener = View.OnClickListener {
                detailsA.isExpanded = !detailsA.isExpanded
                notifyItemChanged(position)

                val isExpandable : Boolean = detailsA.isExpanded
                holder.tvA2.visibility = if (isExpandable) View.VISIBLE else View.GONE
                holder.ibA.setImageResource(if (isExpandable) R.drawable.expand_less else R.drawable.expand_more)
            }

            holder.headerEConstraintLayout.setOnClickListener(mClickListener)
            holder.headerEImageButtonA.setOnClickListener(mClickListener)
            }
            typeB -> {
                val detailsB = mData[position] as ItemB
                (holder as ViewHolderB).showDetails(detailsB)
            }
            typeC -> {
                val detailsC = mData[position] as ItemC
                (holder as ViewHolderC).showDetails(detailsC)
            }
            typeD -> {
                val detailsD = mData[position] as ItemD
                (holder as ViewHolderD).showDetails(detailsD)
            }
        }
    }

    override fun getItemCount(): Int {
        return mData.size
    }

    inner class ViewHolderA(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val itemAcl: ConstraintLayout = itemView.findViewById(R.id.clA)
        private val itemAib: ImageButton = itemView.findViewById(R.id.ibA)
        private val itemA1: TextView = itemView.findViewById(R.id.tvA1)
        private val itemA2: TextView = itemView.findViewById(R.id.tvA2)
    }

    inner class ViewHolderB(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val itemB1: TextView = itemView.findViewById(R.id.tvB1)

        fun showDetails(detailsB: ItemB) {
            val txtB1 = detailsB.txtB1
            itemB1.text = txtB1
        }
    }

    inner class ViewHolderC(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val itemCib: ImageButton = itemView.findViewById(R.id.ibC)
        private val itemC1: TextView = itemView.findViewById(R.id.tvC1)
        private val itemC2: TextView = itemView.findViewById(R.id.tvC2)
        private val itemC3: TextView = itemView.findViewById(R.id.tvC3)
        private val itemC4: TextView = itemView.findViewById(R.id.tvC4)

        fun showDetails(detailsC: ItemC) {
            val txtC1 = detailsC.txtC1
            val txtC2 = detailsC.txtC2
            val txtC3 = detailsC.txtC3
            val txtC4 = detailsC.txtC4
            itemC1.text = txtC1
            itemC2.text = txtC2
            itemC3.text = txtC3
            itemC4.text = txtC4
        }
    }

    inner class ViewHolderD(itemView: View) : RecyclerView.ViewHolder(itemView) {
        private val itemD1: TextView = itemView.findViewById(R.id.tvD1)
        private val itemD2: TextView = itemView.findViewById(R.id.tvD2)
        private val itemD3: TextView = itemView.findViewById(R.id.tvD3)
        private val itemD4: TextView = itemView.findViewById(R.id.tvD4)

        fun showDetails(detailsD: ItemD) {
            val txtD1 = detailsD.txtD1
            val txtD2 = detailsD.txtD2
            val txtD3 = detailsD.txtD3
            val txtD4 = detailsD.txtD4
            itemD1.text = txtD1
            itemD2.text = txtD2
            itemD3.text = txtD3
            itemD4.text = txtD4
        }
    }
}

Item A class

data class ItemA(val txtA1: String,
                 val txtA2: String,
                 var isExpanded: Boolean = false)

Item B class

data class ItemB(val txtB1: String)

Item C class

data class ItemC(val txtC1: String,
                 val txtC2: String,
                 val txtC3: String,
                 val txtC4: String,
                 var isExpanded: Boolean = false)

Item D class

data class ItemD(val txtD1: String,
                 val txtD2: String,
                 val txtD3: String,
                 val txtD4: String)

enter image description here

Update

enter image description here


Solution

  • I think the issue is with this line in the adapter val isExpandable : Boolean = mData[position].isExpanded You're basically using the getPosition() function of the adapter. If you must have the click listener in the adapter, put it in onBindViewHolder instead, this way you have the position parameter that's more accurate since you have more than one type of list item