我正在尝试将ListAdapter与Room和LifeData一起使用。但是我遇到了DiffUtil.ItemCallback的奇怪行为-areContentsTheSame()方法中的对象始终相同。 添加和删除对象没有问题,但是更改内容没有问题。
物品类别:
@Entity(tableName = "item")
data class Item(var num: Int) {
@PrimaryKey(autoGenerate = true)
var key: Int = 0
}
适配器类
class LifeAdapter : ListAdapter<Item, LifeAdapter.ViewHolder>(DiffCallback()) {
private class DiffCallback : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item) = oldItem.key == newItem.key
override fun areContentsTheSame(oldItem: Item, newItem: Item) = oldItem.num == newItem.num
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_item, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, pos: Int) {
val position = holder.layoutPosition
holder.bind(getItem(position))
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(item: Item) {
itemView.findViewById<TextView>(R.id.txt_num).text = item.num.toString()
itemView.findViewById<TextView>(R.id.txt_key).text = item.key.toString()
}
}
}
活动分类:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dao = getDao(this)
val data = dao.getAllItems()
val adapter = LifeAdapter()
rv.layoutManager = LinearLayoutManager(this)
rv.adapter = adapter
val nameObserver = Observer<List<Item>> { adapter.submitList(it) }
data.observe(this, nameObserver)
btn_add.setOnClickListener {
val item = Item(Random.nextInt(0, 1000))
runAsync { dao.insertItem(item) }
}
btn_change.setOnClickListener { v ->
data.value.let {
if (it!!.isNotEmpty()) {
it[0].num = 111
runAsync { dao.updateItem(it[0]) }
}
}
}
btn_delete.setOnClickListener { v ->
data.value.let {
if (it!!.isNotEmpty()) {
runAsync { dao.deleteItem(it[0]) }
}
}
}
}
}
完整项目-https://yadi.sk/d/7tpzDhUA-udoIQ
视频-https://youtu.be/PZYeAfGzXBg
问题出在方法areContentsTheSame()中的LifeAdapter.DiffCallback类中。 如果项目内容(数量)发生变化,则在此方法中,newItem和oldItem相同并且等于新项目:
这意味着方法areContentsTheSame()始终返回true。 我通过链接检查了相等性(newItem === oldItem),它总是应该为假。 我不明白怎么了。通过adapter.submitList()方法添加新列表时,newItem和oldItem必须不同。
答案 0 :(得分:1)
LiveData返回列表中的相同实例。
我找到的解决方案-创建带有项目副本的新列表:
val nameObserver = Observer<List<Item>> {
val newList = mutableListOf<Item>()
it.forEach { item -> newList.add(item.copy()) }
adapter.submitList(newList)
}
答案 1 :(得分:1)
由于LiveData
返回相同的结果 List
,因此您必须创建一个新的
以下是通过使用toList()
对原始答案的简短答案。
recycler.observe(this, Observer{
adapter.submitList(it.toList())
})
答案 2 :(得分:1)
科特林与数据类
adapter.submutList(list.map { it.copy() })
答案 3 :(得分:0)
替换此代码:
btn_change.setOnClickListener { v ->
data.value.let {
if (it!!.isNotEmpty()) {
it[0].num = 111
runAsync { dao.updateItem(it[0]) }
}
}
}
这样:
btn_change.setOnClickListener { v ->
data.value.let {
if (it!!.isNotEmpty()) {
runAsync { dao.updateItem(it.set(0, Item(111))) }
}
}
}