'android Change background color of odd rows in RecyclerView when using DiffUtil

I have a RecyclerView and Every odd row has a different background color. I try to add DiffUtil to speed up the updates like this:


import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.asdf.android.R
import com.asdf.android.network.model.trade.MarketTradeItem
import kotlinx.android.synthetic.main.row_trade_history.view.*

class MarketTradesListAdapter(
    private val context: Context,
    private var list: MutableList<MarketTradeItem>,
    val theme: Int
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflate =
            LayoutInflater.from(parent.context).inflate(R.layout.row_trade_history, parent, false)
        return ItemHolder(inflate)
    }

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

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val itemHolder = holder as ItemHolder
        itemHolder.bind(list[position], position)
    }

    override fun onBindViewHolder(
        holder: RecyclerView.ViewHolder,
        position: Int,
        payloads: MutableList<Any>
    ) {
        if (payloads.isEmpty()) {
            super.onBindViewHolder(holder, position, payloads)
        } else {
            val payload = payloads[0] as DiffUtilPayload
            val itemHolder = holder as ItemHolder
            itemHolder.bind(list[position], position, payload)
        }
    }

    fun setList(it: List<MarketTradeItem>) {
        it.forEachIndexed { index, item -> item.position = index }

        DiffUtil.calculateDiff(DiffCallback(list, it),true).dispatchUpdatesTo(this)

        list.clear()
        list.addAll(it)
    }

    inner class ItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(
            order: MarketTradeItem,
            position: Int,
            payload: DiffUtilPayload = DiffUtilPayload()
        ) {


            var color: Int
            if (theme == R.style.Apptheme) {
                color = R.color.listBackgroundColorLight
            } else {
                color = R.color.listBackgroundColorDark
            }
//            if (payload.isPositionChanged)
            itemView.setBackgroundColor(
                if (position % 2 == 0) ContextCompat.getColor(
                    itemView.context,
                    android.R.color.transparent
                ) else
                    ContextCompat.getColor(itemView.context, color)
            )


            itemView.textViewPrice.setTextColor(
                ContextCompat.getColor(
                    itemView.context,
                    if (order.isRaise) R.color.buy_green else R.color.sell_red
                )
            )
            if (payload.isPriceChanged) {
                itemView.textViewPrice.text = order.price
            }
            if (payload.isAmountChanged) {
                itemView.textViewAmount.text = order.amount
            }
            if (payload.isTimeChanged) {
                itemView.textViewTime.text = order.time
            }


        }
    }

    class DiffCallback(
        private val oldList: List<MarketTradeItem>,
        private val newList: List<MarketTradeItem>
    ) : DiffUtil.Callback() {
        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return oldList[oldItemPosition] == newList[newItemPosition]
        }

        override fun getOldListSize(): Int {
            return oldList.size
        }

        override fun getNewListSize(): Int {
            return newList.size
        }

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return oldList[oldItemPosition] == newList[newItemPosition]
        }

        override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
            val oldItem = oldList[oldItemPosition]
            val newItem = newList[oldItemPosition]
            return DiffUtilPayload(
                oldItem.price != newItem.price,
                oldItem.amount != newItem.amount,
                oldItem.createdAt != newItem.createdAt,
                oldItem.time != newItem.time,
                oldItem.position != newItem.position
            )
        }

    }

    data class DiffUtilPayload(
        val isPriceChanged: Boolean = true,
        val isAmountChanged: Boolean = true,
        val isCreatedAtChanged: Boolean = true,
        val isTimeChanged: Boolean = true,
        val isPositionChanged: Boolean = true
    )

}

The problem is that the background color of even and odd rows does not appear correctly when new items are inserted to the list and appears like this:

enter image description here The background color is set randomly and not appear as alternate even/odd. What can I do to fix this?



Solution 1:[1]

I think you need to change areContentsTheSame method in your DiffUtil. If the contents are same, it won't calculate the change which won't dispatch notifyItemChanged(position) to the adapter. And it won't call onBindViewHolder for that position/item.

You should try changing the method to

override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
    return oldList[oldItemPosition] == newList[newItemPosition] && oldItemPosition % 2 == newItemPosition % 2
}

Solution 2:[2]

if items are added at the beginning. the fast solution would be, in onBindViewHolder

itemHolder.bind(list[position], position, payload)

change to:

itemHolder.bind(list[position], getItemCount() - position, payload)

and itemHolder.bind(list[position], position)

change to:

itemHolder.bind(list[position], getItemCount() - position)

I think the view holder should not know the postion. so I suggest you some refactoring.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Froyo
Solution 2 Aleksadnre Bibilashvili