Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/233.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 带有DiffUtil.ItemCallback的ListAdapter始终认为对象是相同的_Android_Android Recyclerview - Fatal编程技术网

Android 带有DiffUtil.ItemCallback的ListAdapter始终认为对象是相同的

Android 带有DiffUtil.ItemCallback的ListAdapter始终认为对象是相同的,android,android-recyclerview,Android,Android Recyclerview,我正在尝试将ListAdapter用于Room和LifeData。但是我遇到了DiffUtil.ItemCallback的奇怪行为——areContentsTheSame()方法中的对象总是相同的。 添加和删除对象没有问题,但更改内容有问题 项目类别: @Entity(tableName = "item") data class Item(var num: Int) { @PrimaryKey(autoGenerate = true) var key: Int = 0 }

我正在尝试将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-LifeAdapter:ListAdapter(DiffCallback()){
私有类DiffCallback:DiffUtil.ItemCallback(){
覆盖乐趣项目相同(oldItem:Item,newItem:Item)=oldItem.key==newItem.key
覆盖相同的内容(oldItem:Item,newItem:Item)=oldItem.num==newItem.num
}
override onCreateViewHolder(父级:ViewGroup,viewType:Int):ViewHolder{
val view=LayoutInflater.from(parent.context)。充气(R.layout.item\u item,parent,false)
返回视图保持器(视图)
}
覆盖BindViewHolder(holder:ViewHolder,位置:Int){
val位置=保持架。布局位置
持有者绑定(获取项目(位置))
}
类ViewHolder(视图:视图):RecyclerView.ViewHolder(视图){
趣味绑定(物品:物品){
itemView.findViewById(R.id.txt_num).text=item.num.toString()
itemView.findViewById(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]) }
                }
            }
        }

    }
}
class MainActivity:AppCompatActivity(){
重写创建时的乐趣(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val dao=getDao(这个)
val data=dao.getAllItems()
val adapter=LifeAdapter()
rv.layoutManager=LinearLayoutManager(此)
rv.适配器=适配器
val nameObserver=Observer{adapter.submitList(it)}
数据。观察(此名称,观察者)
btn_add.setOnClickListener{
val项目=项目(Random.nextInt(0,1000))
runAsync{dao.insertItem(项)}
}
btn_change.setOnClickListener{v->
data.value.let{
if(it!!.isNotEmpty()){
它[0]。num=111
runAsync{dao.updateItem(it[0])}
}
}
}
btn_delete.setOnClickListener{v->
data.value.let{
if(it!!.isNotEmpty()){
runAsync{dao.deleteItem(它[0])}
}
}
}
}
}
完整项目-

视频-

问题出在方法AreContentsSame()中的LifeAdapter.DiffCallback类中。 如果项目内容(num)发生变化,则在此方法中,newItem和oldItem都相同并等于new item:

这意味着该方法是contentsSame()始终返回true。 我通过链接检查了相等性(newItem==oldItem),它始终是false。
我不明白怎么了。通过adapter.submitList()方法添加新列表时,newItem和oldItem必须不同

LiveData返回列表中相同的实例

我找到的解决方案-使用项目副本创建新列表:

    val nameObserver = Observer<List<Item>> {
        val newList = mutableListOf<Item>()
        it.forEach { item -> newList.add(item.copy()) }
        adapter.submitList(newList)
    }
val nameObserver=Observer{
val newList=mutableListOf()
it.forEach{item->newList.add(item.copy())}
adapter.submitList(新列表)
}

由于
LiveData
返回相同的
列表
您必须创建一个新列表

以下是使用
toList()
对原始答案的简短回答

如果您更愿意使用kotlin扩展,可以执行以下操作:

fun <T> MutableLiveData<List<T>>.add(item: T) {
    val updatedItems = this.value?.toMutableList()
    updatedItems?.add(item)
    this.value = updatedItems
}
fun MutableLiveData.add(项:T){
val updateItems=this.value?.toMutableList()
UpdateItems?.add(项目)
this.value=updateItems
}

这样,您就不必添加
toList()
,只需使用扩展即可。

Kotlin与数据类一起使用

adapter.submutList(list.map { it.copy() })
替换此代码:

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

我的问题和这里的问题一样。我试过你的建议,但对我不起作用。看起来传递给submitList()的列表从来都不一样,所以使用您的建议并没有改变这一点。列表总是一样的,内容不是这样。这就是为什么您添加了
.toList()
。实际上,我是在手动更新LiveData对象,然后调用了submitList。当我更新LiveData对象时,UI首先得到更新。所以几秒钟后,当submitList被调用时,列表已经是相同的了。@Leonebaventura你是如何解决的?@Leonebaventura我也面临着同样的问题,你能分享你的解决方案吗?列表来自哪里
it
copy()
@FelixPK有一个未解析的引用,它应该是一个数据类列表。数据类具有创建相同对象的复制函数,但其内存中的引用不同。
btn_change.setOnClickListener { v ->
            data.value.let {
                if (it!!.isNotEmpty()) {
                    runAsync { dao.updateItem(it.set(0, Item(111))) }
                }
            }
        }