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 14

2 ответа:

Edit: я понимаю, почему это происходит, но это не моя точка зрения. Я хочу сказать, что он, по крайней мере, должен дать предупреждение или вызвать функцию notifyDataSetChanged(). Потому что, по-видимому, я вызываю функцию submitList(...) не просто так. Я почти уверен, что люди пытаются выяснить, что пошло не так в течение нескольких часов, пока они не выяснят, что submitList() молча игнорирует вызов.

Это из-за странной логики Google. Поэтому, если вы передадите тот же список адаптеру, он даже не вызовет 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.