这是情况:
我使用RecyclerView
在Fragment
中有一个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
}
}
注意:
update()
方法会更改列表的值,例如:data[0] = someValue
。它既不使用clear()
也不使用addAll()
进行更新。
ListAdapter.onCurrentListChanged()
只是为了将println()
放在其中。在这一点上,没有什么特别的。创建片段后,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不会刷新,因为我没有分配新列表,而只更新了当前列表。此外,如果我导航到另一个片段然后返回,则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()
,但在两张照片的末尾而不是中间。
另外,ListAdapter.currentList
似乎在“提交后”打印中包含值,但实际上在onCurrentListChanged()
打印中为空。令人困惑...
我发现进行RecyclerView
刷新的唯一方法是调用notifyDataSetChanged()
。但是,使用ListAdapter
及其submitList()
方法没有好处。
作为一个新手,我做的事情可能不正确,但是我不知道该怎么做。
问题仅在于用户界面不刷新。我在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
}
答案 0 :(得分:0)
这是与浅拷贝和深拷贝之间的差异有关的问题。
如本article关于ListAdapter
所述:
很高兴知道,
ListAdapter
保留了对submitList()
中提供的列表的引用。始终确保提供带有其他项目实例的其他列表。如果对项目的引用相同,则DiffUtil
将比较始终相等的相同项目,并且RecyclerView
不会更新。