ListAdapter не обновляет элемент в reyclerview
Я использую новую библиотеку поддержки ListAdapter
. Вот мой код для адаптера
class ArtistsAdapter : ListAdapter<Artist, ArtistsAdapter.ViewHolder>(ArtistsDiff()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(parent.inflate(R.layout.item_artist))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(getItem(position))
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(artist: Artist) {
itemView.artistDetails.text = artist.artistAlbums
.plus(" Albums")
.plus(" u2022 ")
.plus(artist.artistTracks)
.plus(" Tracks")
itemView.artistName.text = artist.artistCover
itemView.artistCoverImage.loadURL(artist.artistCover)
}
}
}
Я обновляю адаптер с помощью
musicViewModel.getAllArtists().observe(this, Observer {
it?.let {
artistAdapter.submitList(it)
}
})
Мой класс различий
class ArtistsDiff : DiffUtil.ItemCallback<Artist>() {
override fun areItemsTheSame(oldItem: Artist?, newItem: Artist?): Boolean {
return oldItem?.artistId == newItem?.artistId
}
override fun areContentsTheSame(oldItem: Artist?, newItem: Artist?): Boolean {
return oldItem == newItem
}
}
Что происходит, когда submitList вызывается в первый раз, когда адаптер отображает все элементы, но когда submitList вызывается снова с обновленными свойствами объекта, он не повторно отображает представление, которое изменилось.
Он повторно отображает представление, когда я прокручиваю список, который в свою очередь вызывает bindView()
Кроме того, у меня есть заметил, что вызов adapter.notifyDatasSetChanged()
после отправки списка отображает представление с обновленными значениями, но я не хочу вызывать notifyDataSetChanged()
, потому что адаптер списка имеет встроенный diff utils
2 ответа:
Edit: я понимаю, почему это происходит, но это не моя точка зрения. Я хочу сказать, что он, по крайней мере, должен дать предупреждение или вызвать функцию
notifyDataSetChanged()
. Потому что, по-видимому, я вызываю функциюsubmitList(...)
не просто так. Я почти уверен, что люди пытаются выяснить, что пошло не так в течение нескольких часов, пока они не выяснят, что submitList() молча игнорирует вызов.Это из-за странной логики
DiffUtil
.Я действительно не понимаю весь смысл этогоpublic void submitList(final List<T> newList) { if (newList == mList) { // nothing to do return; } .... }
ListAdapter
, если он не может обрабатывать изменения в том же списке. Если вы хотите изменить элементы в списке, вы переходите кListAdapter
и видите изменения, то вам нужно либо создать глубокую копию списка, либо использовать обычныйRecyclerView
с вашим собственным классомDiffUtill
.
Библиотека предполагает, что вы используете Room или любой другой ORM, который предлагает новый асинхронный список каждый раз, когда он обновляется, поэтому просто вызов submitList на нем будет работать, а для неаккуратных разработчиков это предотвращает выполнение вычислений дважды, если вызывается один и тот же список.
Принятый ответ верен, он предлагает объяснение, но не решение.Что вы можете сделать, если вы не используете такие библиотеки, это:
submitList(null); submitList(myList);
Другим решением было бы переопределить submitList (что не вызывает такого быстрого мигания) как таковой:
@Override public void submitList(final List<Author> list) { super.submitList(list != null ? new ArrayList<>(list) : null); }
Немного отсталая логика, но работает отлично. Мой предпочтительный метод-второй, потому что он не заставляет каждую строку получать вызов onBind.