如何在 Recyclerview 中正确使用 DiffUtil 更新数组列表?

Posted

技术标签:

【中文标题】如何在 Recyclerview 中正确使用 DiffUtil 更新数组列表?【英文标题】:How to properly use DiffUtils in Recycler view to update array list? 【发布时间】:2021-12-07 04:41:32 【问题描述】:

我正在为 recyclerview 实现 diffutils 以通知列表。在搜索过滤器时,recyclerview diffutils 有效。但是当我单击列表项应用程序崩溃时 java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 同时当我使用 notifyDataSetChanged() 时应用程序没有崩溃。

模型类

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
)

适配器类

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 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)
    


我需要使用 diffutils 更新 recyclerview 请提及他们在我的代码中是否有任何更正

提前致谢

【问题讨论】:

【参考方案1】:

你可以查看这个 repo Githup ripo

我尝试编辑您的代码

&lt;script src="https://gist.github.com/alihrhera/109ec71245e40c953451a68627a1dc60.js"&gt;&lt;/script&gt;

run time gif gits the code

【讨论】:

感谢您的评论。我也在做同样的事情。一切正常,但 recyclerview 没有更新,这是我的问题 执行 whta 时不更新?添加或删除或编辑项目? 搜索过滤时 过滤代码在哪里? 我添加我的过滤器查询请检查【参考方案2】:

过滤查询

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()
    

【讨论】:

以上是关于如何在 Recyclerview 中正确使用 DiffUtil 更新数组列表?的主要内容,如果未能解决你的问题,请参考以下文章

一起Talk Android吧(第五百零一回:如何正确地更新RecyclerView中的数据)

如何使用 LiveData 正确更新 Android 的 RecyclerView?

如何正确设置recyclerview的高程值?

如何正确突出显示 RecyclerView 上的选定项目?

在带有 RecyclerView 的 NestedScrollView 中无法正确显示过度滚动效果

如何在AsyncTask中将Jsoup数据设置为RecyclerView