Home > Back-end >  How to properly use DiffUtils in Recycler view to update array list?
How to properly use DiffUtils in Recycler view to update array list?

Time:10-21

I am implementing diffutils for recyclerview to notify list. While Search filter the recyclerview diffutils works. But when I click the list item app crash with java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 at the same time when i use notifyDataSetChanged() app did not crash.

Model Class

data class LanguageModel (
    @SerializedName("languageName")
    var languageName : String = "",
    @SerializedName("languageNativeName")
    var languageNativeName : String = "",
    @SerializedName("languageCode")
    var languageCode : String = "",
    @SerializedName("updatedAt")
    var updatedAt : String = "",
    @SerializedName("defaultLanguage")
    var defaultLanguage : Boolean = false
)

Adapter Class

class LanguageSelectionAdapter(var languageModelList : ArrayList<LanguageModel>, var itemClick : LanguageClick)
    : RecyclerView.Adapter<LanguageSelectionAdapter.LanguageSelectionVH>() {

    inner class LanguageSelectionVH(val binding: LanguageListSingleItemBinding)
        : RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LanguageSelectionVH {
        val binding = LanguageListSingleItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return LanguageSelectionVH(binding)
    }

    override fun onBindViewHolder(holder: LanguageSelectionVH, position: Int) {
        val model = languageModelList[position]
        holder.binding.languageCard.apply {
            if (position == 0 && position % 2 == 0) {
                setCardBackgroundColor(ContextCompat.getColor(context, R.color.main_blue))
            } else {
                setCardBackgroundColor(ContextCompat.getColor(context, R.color.main_green))
            }
        }
        holder.binding.nativeLanguageText.text = model.languageNativeName
        holder.binding.originalLanguageText.text = model.languageName
        holder.itemView.setOnClickListener {
            itemClick.langClick(position)
        }
    }

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

    fun setData(newLanguageModelList : ArrayList<LanguageModel>) {
        val diffCallback = LanguageSelectionDiffUtils(languageModelList, newLanguageModelList)
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        languageModelList.clear()
        languageModelList.addAll(newLanguageModelList)
        diffResult.dispatchUpdatesTo(this)
    }

}

Diffutil Class

class LanguageSelectionDiffUtils(
    private val oldList : ArrayList<LanguageModel>,
    private val newList : ArrayList<LanguageModel>
) : DiffUtil.Callback(){

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

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

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

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val (languageName, languageNativeName, languageCode, updatedAt,defaultLanguage) = oldList[oldItemPosition]
        val (languageName1, languageNativeName1, languageCode1, updatedAt1,defaultLanguage1) = newList[newItemPosition]
        return languageName == languageName1
                        && languageNativeName == languageNativeName1
                        && languageCode == languageCode1
                        && updatedAt == updatedAt1
                        && defaultLanguage == defaultLanguage1
    }


    @Nullable
    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
        return super.getChangePayload(oldItemPosition, newItemPosition)
    }

}

I need to update recyclerview using diffutils please mention is their is any correction in my code

Thanks in advance

CodePudding user response:

Filter Query

private fun perFormFilter(filterText : String) {
        languageList = ArrayList()
        if (filterText.isEmpty() || filterText == null) {
            languageList = languageMainList
        } else {
            for (i in 0 until languageMainList.size) {
                if (languageMainList[i].languageName.lowercase(Locale.ROOT).contains(filterText.lowercase(Locale.ROOT)) ||
                    languageMainList[i].languageNativeName.lowercase(Locale.ROOT).contains(filterText.lowercase(Locale.ROOT)) ||
                    languageMainList[i].languageCode.lowercase(Locale.ROOT).contains(filterText.lowercase(Locale.ROOT))
                ) {
                    languageList.add(languageMainList[i])
                }
            }
        }
        languageSelectionAdapter.setData(languageList)
        //languageSelectionAdapter.notifyDataSetChanged()
    }

CodePudding user response:

you can chek this repo Githup ripo

i try to edit your code

<script src="https://gist.github.com/alihrhera/109ec71245e40c953451a68627a1dc60.js"></script>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

run time gif gits the code

  • Related