gpt4 book ai didi

android - RecyclerView 不会使用 submitList() 和 LiveData 自动刷新

转载 作者:行者123 更新时间:2023-12-04 15:26:56 28 4
gpt4 key购买 nike

情况是这样的:

我有一个 RecyclerViewFragment使用 DataBinding .它的适配器是 ListAdapter .

class MyFragment : Fragment() {
override fun onCreateView(...) {
val binding = // inflate layout with DataBindingUtil

val myListAdapter = MyListAdapter()
binding.recyclerView.adapter = myListAdapter

val myViewModel: MyViewModel by activityViewModels()
myViewModel.myLiveData.observe(viewLifecycleOwner, Observer {
println("before submit: ${myListAdapter.currentList}")
myListAdapter.submitList(it)
println("after submit: ${myListAdapter.currentList}")
})

return binding.root
}
}

要显示的数据由 List<Double> 表示.设置后,列表用于初始化 MutableLiveData如下:

class MyViewModel : ViewModel() {
val data = listOf<Double>(/* init with some values */)
val myLiveData = MutableLiveData(data)

fun onButtonClicked() {
update()
println(myLiveData.value) // LiveData is correctly updated according to data
}
}

Note: the update() method changes the list's values like: data[0] = someValue. It does not use clear() nor addAll() to update it.

  • 此外,我覆盖了ListAdapter.onCurrentListChanged()只放一个println()里面。

在这一点上,没有什么特别的。创建 fragment 时,RecyclerView显示初始列表。在 Logcat 中:

I/System.out: before submit: []
I/System.out: onCurrentListChanged: [] -> [4.07, 6.29, 13.85, 17.92, 21.42, 23.47, 1.85]
I/System.out: after submit: [4.07, 6.29, 13.85, 17.92, 21.42, 23.47, 1.85]

现在,当我单击按钮时,UI 不会刷新,因为我没有分配新列表,而只更新了当前列表。此外,如果我导航到另一个 fragment 然后返回,RecyclerView正在显示更新的值。

所以我在 onButtonClicked() 末尾添加以下内容:

myLiveData.value = myLiveData.value

但这不起作用,点击按钮后 UI 仍然没有自动更新。此外,Logcat 仅打印“提交前”和“提交后”,与 ListAdapter.currentList 相同值:

I/System.out: before submit: [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85]
I/System.out: after submit: [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85]

对我来说,打印品应该看起来像这样:

I/System.out: before submit: [4.07, 6.29, 13.85, 17.92, 21.42, 23.47, 1.85]
I/System.out: onCurrentListChanged: [4.07, 6.29, 13.85, 17.92, 21.42, 23.47, 1.85] -> [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85]
I/System.out: after submit: [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85]

看来 ListAdapter.currentList甚至在调用 submitList() 之前就已经更新了值.我想这就是为什么 RecyclerView不刷新,因为提交的列表与当前列表相同。
我还在 onButtonClicked() 的末尾尝试了以下内容没有成功:

//myLiveData.value = myLiveData.value
myLiveData.value = emptyList()
myLiveData.value = data

还有这个……

//myLiveData.value = myLiveData.value
myLiveData.value = emptyList()
//myLiveData.value = data

... 给我:

I/System.out: before submit: [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85]
I/System.out: after submit: [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85]
I/System.out: onCurrentListChanged: [4.88, 6.77, 13.85, 17.76, 20.93, 22.69, 1.85] -> []

现在onCurrentListChanged()被调用但在 2 次打印的末尾而不是在中间。
另外,ListAdapter.currentList似乎包含“提交后”打印中的值,但实际上在 onCurrentListChanged() 中为空打印。令人困惑...

我发现制作 RecyclerView 的唯一方法刷新就是调用notifyDataSetChanged() .但是,使用 ListAdapter 没有任何好处。及其 submitList()方法。

作为一个新手,我可能做错了什么,但我不知道是什么。
问题仅与 UI 不刷新有关。我可以在 Locgcat 中看到数据正在正确更新。

提前致谢

编辑

class MyListAdapter() : ListAdapter<Double, MyViewHolder>(MyDiffCallBack()) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
MyViewHolder.from(parent, itemCount)

override fun onBindViewHolder(holder: MyViewHolder, position: Int) =
holder.bind(getItem(position))

override fun onCurrentListChanged(previousList: MutableList<Double>, currentList: MutableList<Double>) {
super.onCurrentListChanged(previousList, currentList)
println("onCurrentListChanged: $previousList -> $currentList")
}
}

class MyViewHolder private constructor(private val binding: MyItemViewBinding) : RecyclerView.ViewHolder(binding.root) {

fun bind(data: Double) {
binding.dataTxt.text = data.toString()
}

companion object {
fun from(parent: ViewGroup, itemCount: Int): MyViewHolder {
val binding = // inflate layout
binding.root.layoutParams.height = parent.height / itemCount // set the height proportionally
return MyViewHolder(binding)
}
}
}

class MyDiffCallBack : DiffUtil.ItemCallback<Double>() {
override fun areItemsTheSame(oldItem: Double, newItem: Double): Boolean = oldItem == newItem

override fun areContentsTheSame(oldItem: Double, newItem: Double): Boolean = oldItem == newItem

}

最佳答案

这是一个关于浅拷贝和深拷贝区别的问题。
如本article所述关于 ListAdapter:

Good to know is that the ListAdapter keeps a reference towards the provided list in submitList(). Always make sure to provide an other list with other item instances. If the references to the items are the same, DiffUtil compares the same items which are always equal, and the RecyclerView will not be updated.

关于android - RecyclerView 不会使用 submitList() 和 LiveData 自动刷新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62068521/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com