ListAdapter submitList 未更新

Posted

技术标签:

【中文标题】ListAdapter submitList 未更新【英文标题】:ListAdapter submitList not updating 【发布时间】:2022-01-03 11:03:02 【问题描述】:

我在 RecyclerView 中遇到了分页无限滚动的问题,我正在使用 .addAll() 添加所有新项目

 movieList.addAll(it.movieList)
 adapter.submitList(movieList)
 Log.wtf("WTF", movieList.size.toString())

每当我们从 API 获得成功响应时,大小就会不断增加,这表明列表确实正在填充,但 RecyclerView 中的项目保持不变,submitList() 似乎只在第一次调用时起作用。

这是我的 DiffUtil 类和适配器

class DiffUtilMovies : DiffUtil.ItemCallback<MovieItem>() 

    // DiffUtil uses this test to help discover if an item was added, removed, or moved.
    override fun areItemsTheSame(oldItem: MovieItem, newItem: MovieItem): Boolean 
        return oldItem.id == newItem.id
    

    // Check whether oldItem and newItem contain the same data; that is, whether they are equal.
    // If there are differences between oldItem and newItem, this code tells DiffUtil that the item has been updated.
    override fun areContentsTheSame(oldItem: MovieItem, newItem: MovieItem): Boolean 
        // Check for now if there is a difference on the price, removing specific fields
        // means checking all the data for changes
        return oldItem.title == newItem.title
    




class MovieAdapter(private val context: Context) : ListAdapter<MovieItem, MovieAdapter.ItemView>(DiffUtilMovies()) 

    private var isDetached: Boolean = false

    class ItemView(itemView: MovieCardBinding) : RecyclerView.ViewHolder(itemView.root) 
        val titleTxt = itemView.titleTxt
        val rateTxt = itemView.rateTxt
        val rateBar = itemView.rateBar
        val imageThumb = itemView.thumbnail
    

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemView 
        return ItemView(
            MovieCardBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )
    

    override fun onBindViewHolder(holder: ItemView, position: Int) 
        holder.apply 

            val movieItem = getItem(position)

            titleTxt.text = movieItem.title
            rateTxt.text = movieItem.voteAverage.toString()

            val rateAvg = movieItem.voteAverage?.toFloat() ?: run 
                0.0f
            

            rateBar.rating = rateAvg/2

            if (!isDetached)
                GlideApp.with(context)
                    .load(context.getString(R.string.image_link,AppConfig.image_endpoint, movieItem.posterPath))
                    .thumbnail(GlideApp.with(context).load(R.drawable.loading).centerCrop())
                    .error(R.drawable.no_image)
                    .into(imageThumb)

            this.itemView.setOnClickListener 

                try 

//                    context.startActivity(Intent(context, AssetInfoActivity::class.java).apply 
//                        putExtra(context.getString(R.string.assets), movieItem)
//                    )

                
                catch (ignored: Exception)
                    // The user probably already leave before the activity started
                

            

        
    

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) 
        super.onDetachedFromRecyclerView(recyclerView)
        isDetached = true
    

【问题讨论】:

【参考方案1】:

ListAdapter 不适用于可变列表。这是因为如果您修改 List 的内容,当它尝试比较旧列表和新列表的内容时,它会将同一个列表与自身进行比较。没有旧的列表实例仍然保存旧的内容,因此它无法检测到任何差异。

您应该创建一个新列表,而不是改变原始列表,例如

movieList = movieList + it.movieList
adapter.submitList(movieList)

或者,您可以使用可变后备列表,但在将其传递给submitList 时始终创建一个副本。即使是第一次传递 List 时,您也必须使用副本,这样它就永远不会引用您的可变 List。

movieList.addAll(it.movieList)
adapter.submitList(movieList.toList())

【讨论】:

是的,现在刚刚修好了。无论如何谢谢,我仍然会标记这个答案 但是我仍然看到一些重复的项目,AFAIK DiffUtil 应该已经删除了重复的条目吧? 它不会删除重复项。 submitList 之后的列表中的项目将与您传递给它的列表中的项目完全匹配。 哦,我认为它还包括避免重复项。感谢您的信息。 DiffUtil 不负责对您的列表进行任何修改。您可以确保新列表按照您希望它们出现的顺序准确地包含您想要的项目。 DiffUtil 只负责找出如何以最有效的方式更改代表旧显示列表的视图持有者以匹配您的新列表。当您致电 submitList() 时,您是在说:“这个新列表正是我希望 ReyclerView 显示的内容。让它发生。”

以上是关于ListAdapter submitList 未更新的主要内容,如果未能解决你的问题,请参考以下文章

带有 ListAdapter 的 RecyclerView

当视图更新 Android Kotlin 时,DiffUtil 不与 ListAdpater 一起使用

拖放 RecyclerView 的第一项会移动几个随机位置

久未更 ~ 三之 —— CardView简单记录

JList的使用 未更完

PITR 后 recovery.conf 未更改为 recovery.done