【问题标题】:Kotlin ListAdapter reset RecyclerView after submitListKotlin ListAdapter 在 submitList 后重置 RecyclerView
【发布时间】:2021-11-28 04:58:56
【问题描述】:

我正在使用 MVVM 和数据绑定开发 Android 应用程序。我正在为我的 RecyclerView 适配器使用 ListAdapter。情况是,当我使用 submitList 向适配器提交新数据时,它会重置 RecyclerView 滚动位置。一开始它会闪烁,然后将其位置重置到顶部。

我的绑定适配器

@BindingAdapter("listTemplate", "hirarki")
fun bindListTemplate(recyclerView: RecyclerView, data: List<Template>?, hirarki: Int) {
        var adapter = recyclerView.adapter as TemplateChiefAdapter
        adapter.submitList(data)


}

TemplateFragment 我重新提交数据的地方

 navController.currentBackStackEntry?.savedStateHandle?.getLiveData<Boolean>("shouldUpdate")
            ?.observe(viewLifecycleOwner, {
                if (it) {
                    viewModel.fetchdata()
                    navController.currentBackStackEntry?.savedStateHandle?.remove<Boolean>("shouldUpdate")
                }
            })

这段代码会更新我的 ViewModel 中的 LiveData,所以 DataBinding 会检测到它的变化并重新提交数据给适配器

我的列表适配器

class TemplateChiefAdapter(val onClickListener: OnClickListener) : ListAdapter<Template, TemplateChiefAdapter.TemplateChiefViewHolder>(DiffCallback) {

    class TemplateChiefViewHolder(private var binding: ItemTemplateChiefBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(template: Template) {
            binding.template = template
            binding.executePendingBindings()
        }

    }

    companion object DiffCallback : DiffUtil.ItemCallback<Template>() {
        override fun areItemsTheSame(oldItem: Template, newItem: Template): Boolean {
            return oldItem === newItem
        }

        override fun areContentsTheSame(oldItem: Template, newItem: Template): Boolean {
            return oldItem.id_template == newItem.id_template
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TemplateChiefViewHolder {
        return TemplateChiefViewHolder(ItemTemplateChiefBinding.inflate(LayoutInflater.from(parent.context)))
    }

    override fun onBindViewHolder(holder: TemplateChiefViewHolder, position: Int) {
        val template = getItem(position)
        holder.itemView.setOnClickListener {
            onClickListener.onClick(template)
        }
        holder.bind(template)
    }

    class OnClickListener(val listener: (template: Template) -> Unit) {
        fun onClick(template: Template) = listener(template)
    }
}

如何在 submitList 调用后保持回收站滚动位置?

【问题讨论】:

    标签: android kotlin android-recyclerview data-binding viewmodel


    【解决方案1】:

    我没有仔细检查所有您的代码,但 DiffUtil 回调引起了我的注意。

    areItemsTheSame 是 DiffUtil 类的优化,用于确定项目是否更改了位置。如果没有,则可以检查内容,如果更改,则重新绑定到新数据。如果位置发生了变化,那么项目可能需要在其他地方或其他地方设置动画......正如您可以想象的那样,它会从那里变得更加复杂。

    该方法的想法是比较项目是否相同,而不是比较整个项目。我会使用 id(或任何可以帮助您识别项目唯一性的东西)。您正在使用 === 运算符,我不知道您的体系结构的其余部分,但是如果您的数据层转换并复制这些对象(您不能/应该'不要告诉/关心你的适配器)。

    例如,而不是

    return oldItem === newItem
    

    你可以的

    return oldItem.someId === newItem.someId
    

    这将确保即使您的项目相同但被复制/重新创建/等等,您仍然可以识别它们,尽管它们是不同的参考。

    然后,在 areContentsTheSame 中,您应该检查所有您认为有助于决定是否必须在特定 viewHolder 上调用 onBind 的内容,因为内容不同。所以我会期待更多类似的东西:

    oldItem.something == newItem.something
       && oldItem.xxx == newItem.xxx
       && oldItem.yyy == newItem.yyy
    

    (但也许使用 DataBinding 你不需要这个,我不知道)。

    话虽如此,我有 0.1 的 DataBinding 经验(对我个人而言,这已经足够了),所以如果这与数据绑定库的行为方式有关,我将无法再为您提供帮助。 :/

    从 RecyclerView 的角度来看,其余代码看起来足够

    【讨论】:

      猜你喜欢
      • 2022-01-03
      • 1970-01-01
      • 1970-01-01
      • 2021-03-28
      • 2021-10-12
      • 2020-09-14
      • 1970-01-01
      • 2021-11-20
      • 2021-06-03
      相关资源
      最近更新 更多