recyclerView 中的 diffutil 回调无法正常工作
diffutil callback in recyclerView doesn't work perfectly
我正在尝试在不使用
的情况下在 RecyclerView 列表中添加一些搜索
notifyDataSetChanged()
而不是使用
diffutil.callback()
但问题是它正确更改了列表,但没有正确更改 UI
这是我的代码,我会解释它
class RecordsAdapter : RecyclerView.Adapter<RecordsAdapter.ViewHolder>() {
var adapterList = listOf<CustomerModel>()
var modelList = listOf<CustomerModel>()
set(value) {
adapterList = value
field = value
}
private var modelListFiltered = listOf<CustomerModel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(CustomerCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(adapterList[position])
}
override fun getItemCount(): Int = adapterList.size
fun filter(isFiltered: Boolean, filterSearch: String) {
if (isFiltered) {
val filter = modelList
.filter {
it.name.contains(filterSearch) || it.id.contains(filterSearch)
}
modelListFiltered = filter
}
adapterList = if (isFiltered) modelListFiltered else modelList
val diff = CartDiffUtil(
if (isFiltered) modelList else modelListFiltered,
if (isFiltered) modelListFiltered else modelList
)
DiffUtil.calculateDiff(diff).dispatchUpdatesTo(this)
}
inner class ViewHolder(private var binding: CustomerCellBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(model: CustomerModel) {
binding.let {
it.model = model
it.executePendingBindings()
}
}
}
}
class CartDiffUtil(private val oldList: List<CustomerModel>, private val newList: List<CustomerModel>) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].id == newList[newItemPosition].id
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition] == newList[newItemPosition]
}
所以我正在调用过滤器函数进行过滤,如果有任何过滤器,我将发送两个参数,第二个是搜索。
现在这个场景出现这个问题
0。搜索“”
1.搜索“测试 2”
2。搜索“测试 4”
3.搜索“测试 2”
4.搜索“”
正如您在图片中看到的,当我在“测试 4”之后搜索“测试 2”时,它一直显示“测试 4”,即使我清除了搜索,它也会给我两个单元格“测试 4”而不是一个“测试 2”和一个“测试 4”
希望我的问题很清楚。
谢谢。
我猜你对三个列表属性的处理会导致某些情况,即 DiffUtil 前后可能存在相同的列表实例,因此无法成功比较它们。
此外,当您想使用 DiffUtil 时,使用 ListAdapter 比 RecyclerView.Adapter 更容易。请注意,当您使用 ListAdapter 时,您使用的是 ItemCallback 而不是 Callback。 ItemCallback 更简单。
尝试这样做,只有 modelList
并且当它或过滤器更改时,您确定新列表是什么并将其提交给 ListAdapter 并让它处理更改。
class RecordsAdapter : ListAdapter<CustomerModel, RecordsAdapter.ViewHolder>(CustomerModelCallback) {
var modelList = listOf<CustomerModel>()
set(value) {
field = value
resync()
}
private var filterText: String = ""
private var isFiltered: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(CustomerCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(adapterList[position])
}
fun filter(isFiltered: Boolean, filterText: String = "") {
this.isFiltered = isFiltered
this.filterText = filterText
resync()
}
private fun resync() {
val newList = when {
isFiltered && filterText.isNotEmpty() ->
modelList.filter {
it.name.contains(filterSearch) || it.id.contains(filterSearch)
}
else -> modelList
}
submitList(newList)
}
// view holder...
}
object CustomerModelCallback : DiffUtil.ItemCallback<CustomerModel>() {
override fun areItemsTheSame(oldItem: CustomerModel, newItem: CustomerModel): Boolean =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: CustomerModel, newItem: CustomerModel): Boolean =
oldItem == newItem
}
我正在尝试在不使用
的情况下在 RecyclerView 列表中添加一些搜索notifyDataSetChanged()
而不是使用
diffutil.callback()
但问题是它正确更改了列表,但没有正确更改 UI
这是我的代码,我会解释它
class RecordsAdapter : RecyclerView.Adapter<RecordsAdapter.ViewHolder>() {
var adapterList = listOf<CustomerModel>()
var modelList = listOf<CustomerModel>()
set(value) {
adapterList = value
field = value
}
private var modelListFiltered = listOf<CustomerModel>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(CustomerCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(adapterList[position])
}
override fun getItemCount(): Int = adapterList.size
fun filter(isFiltered: Boolean, filterSearch: String) {
if (isFiltered) {
val filter = modelList
.filter {
it.name.contains(filterSearch) || it.id.contains(filterSearch)
}
modelListFiltered = filter
}
adapterList = if (isFiltered) modelListFiltered else modelList
val diff = CartDiffUtil(
if (isFiltered) modelList else modelListFiltered,
if (isFiltered) modelListFiltered else modelList
)
DiffUtil.calculateDiff(diff).dispatchUpdatesTo(this)
}
inner class ViewHolder(private var binding: CustomerCellBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(model: CustomerModel) {
binding.let {
it.model = model
it.executePendingBindings()
}
}
}
}
class CartDiffUtil(private val oldList: List<CustomerModel>, private val newList: List<CustomerModel>) : DiffUtil.Callback() {
override fun getOldListSize() = oldList.size
override fun getNewListSize() = newList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition].id == newList[newItemPosition].id
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
oldList[oldItemPosition] == newList[newItemPosition]
}
所以我正在调用过滤器函数进行过滤,如果有任何过滤器,我将发送两个参数,第二个是搜索。
现在这个场景出现这个问题
0。搜索“”
1.搜索“测试 2”
2。搜索“测试 4”
3.搜索“测试 2”
4.搜索“”
正如您在图片中看到的,当我在“测试 4”之后搜索“测试 2”时,它一直显示“测试 4”,即使我清除了搜索,它也会给我两个单元格“测试 4”而不是一个“测试 2”和一个“测试 4”
希望我的问题很清楚。
谢谢。
我猜你对三个列表属性的处理会导致某些情况,即 DiffUtil 前后可能存在相同的列表实例,因此无法成功比较它们。
此外,当您想使用 DiffUtil 时,使用 ListAdapter 比 RecyclerView.Adapter 更容易。请注意,当您使用 ListAdapter 时,您使用的是 ItemCallback 而不是 Callback。 ItemCallback 更简单。
尝试这样做,只有 modelList
并且当它或过滤器更改时,您确定新列表是什么并将其提交给 ListAdapter 并让它处理更改。
class RecordsAdapter : ListAdapter<CustomerModel, RecordsAdapter.ViewHolder>(CustomerModelCallback) {
var modelList = listOf<CustomerModel>()
set(value) {
field = value
resync()
}
private var filterText: String = ""
private var isFiltered: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder =
ViewHolder(CustomerCellBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(adapterList[position])
}
fun filter(isFiltered: Boolean, filterText: String = "") {
this.isFiltered = isFiltered
this.filterText = filterText
resync()
}
private fun resync() {
val newList = when {
isFiltered && filterText.isNotEmpty() ->
modelList.filter {
it.name.contains(filterSearch) || it.id.contains(filterSearch)
}
else -> modelList
}
submitList(newList)
}
// view holder...
}
object CustomerModelCallback : DiffUtil.ItemCallback<CustomerModel>() {
override fun areItemsTheSame(oldItem: CustomerModel, newItem: CustomerModel): Boolean =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: CustomerModel, newItem: CustomerModel): Boolean =
oldItem == newItem
}