вот такая ситуация:
У меня 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]
На данный момент, когда я нажимаю кнопку, пользовательский интерфейс не обновляется sh, потому что я не назначал новый список, а только обновлял текущий. Кроме того, если я перейду к другому фрагменту, а затем вернусь, RecyclerView
отображает обновленные значения.
Поэтому я добавляю следующее в конце onButtonClicked()
:
myLiveData.value = myLiveData.value
Но это не работает, после нажатия кнопки пользовательский интерфейс по-прежнему не обновляется автоматически. Более того, 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
refre sh - это позвонить notifyDataSetChanged()
. Но тогда нет никакой пользы от использования ListAdapter
и его метода submitList()
.
Как новичок ie, я, возможно, сделал что-то неправильно, но я не знаю что.
проблема только в том, что пользовательский интерфейс не обновляется. В Locgcat я вижу, что данные обновляются правильно.
Заранее спасибо
EDIT
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
}