web-dev-qa-db-fra.com

ListAdapter ne met pas à jour l'élément dans recyclerview

J'utilise la nouvelle bibliothèque de support ListAdapter. Voici mon code pour l'adaptateur

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)
        }
    }
}

Je mets à jour l'adaptateur avec 

musicViewModel.getAllArtists().observe(this, Observer {
            it?.let {
                artistAdapter.submitList(it)
            }
        })

Ma classe de diff

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
    }
}

Il se produit que lorsque submitList est appelé pour la première fois, l'adaptateur restitue tous les éléments. Toutefois, lorsque submitList est appelé à nouveau avec des propriétés d'objet mises à jour, il ne restitue pas la vue modifiée.

Il ré-affiche la vue lorsque je fais défiler la liste, qui appelle à son tour bindView().

De plus, j'ai remarqué que l'appel de adapter.notifyDatasSetChanged() après la soumission de la liste rend la vue avec les valeurs mises à jour, mais je ne souhaite pas appeler notifyDataSetChanged() car l'adaptateur de liste possède des utilitaires différents.

Quelqu'un peut-il m'aider?

24

Edit: Je comprends pourquoi cela se produit alors que ce n’était pas mon propos. Mon point est qu'il doit au moins donner un avertissement ou appeler la fonction notifyDataSetChanged(). Parce que apparemment j'appelle la fonction submitList(...) pour une raison. Je suis à peu près sûr que les gens essaient de comprendre ce qui ne va pas pendant des heures jusqu'à ce que submitList () ignore l'appel en silence.

Ceci est dû à la logique étrange de Googles. Ainsi, si vous transmettez la même liste à l’adaptateur, il n’appelle même pas DiffUtil

public void submitList(final List<T> newList) {
    if (newList == mList) {
        // nothing to do
        return;
    }
....
}

Je ne comprends vraiment pas tout l'intérêt de cette ListAdapter si elle ne peut pas gérer les modifications de la même liste. Si vous souhaitez modifier les éléments de la liste que vous passez à la ListAdapter et voir les modifications, vous devez soit créer une copie complète de la liste, soit utiliser RecyclerView régulière avec votre propre classe DiffUtill.

26
insa_c

La bibliothèque suppose que vous utilisez Room ou tout autre ORM offrant une nouvelle liste asynchrone à chaque mise à jour. Le seul fait d'appeler submitList dessus fonctionnera, mais empêchera deux fois si la même liste est appelée d'être soumise aux calculs.

La réponse acceptée est correcte, elle offre l'explication mais pas la solution.

Ce que vous pouvez faire si vous n'utilisez pas de telles bibliothèques, c'est:

submitList(null);
submitList(myList);

Une autre solution serait de remplacer submitList (qui ne provoque pas ce clignotement rapide) en tant que tel:

@Override
public void submitList(final List<Author> list) {
    super.submitList(list != null ? new ArrayList<>(list) : null);
}

Un peu de la logique retardée, mais fonctionne parfaitement . Ma méthode préférée est la deuxième, car elle ne provoque pas à chaque ligne pour obtenir un appel onBind.

15
RJFares

Selon le fonctionnaire docs

Chaque fois que vous appelez submitList, il soumet une nouvelle liste à afficher et à afficher. 

C'est pourquoi chaque fois que vous appelez submitList sur la précédente (liste déjà soumise), elle ne calcule pas le Diff et ne notifie pas à l'adaptateur les modifications apportées au jeu de données.

0
Ashu Tyagi

J'ai eu un problème similaire mais le rendu incorrect a été causé par une combinaison de setHasFixedSize(true) et Android:layout_height="wrap_content". Pour la première fois, l'adaptateur a été fourni avec une liste vide afin que la hauteur ne soit jamais mise à jour et qu'elle soit 0. Quoi qu'il en soit, cela a résolu mon problème. Quelqu'un d'autre pourrait avoir le même problème et penserait que c'est un problème dans l'adaptateur. 

0
Jan Veselý