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?
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 Google
s. 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
.
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.
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.
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.