J'utilise un Le problème est que si je Comment forcer Nouveaux résultats: J'ai vérifié le code source de submitList () et au début il y a une vérification: Je pense que c'est le problème. Mais comment le dépasser? Je veux dire, les développeurs ont sûrement pensé à soumettre une liste ordonnée différente? RecyclerView
avec ListAdapter (qui utilise AsyncListDiffer a > pour calculer et animer les changements lorsque la liste est remplacée). soumet ()
une liste, puis réorganise cette liste et submit () code> encore une fois, rien ne se passe.
ListAdapter
à évaluer cette nouvelle liste, même si elle est "la même" (mais l'ordre a changé)? p > public void submitList(@Nullable final List<T> newList) {
final int runGeneration = ++this.mMaxScheduledGeneration;
if (newList != this.mList) {
5 Réponses :
Cette fonction ne sera pas appelée car ListAdapter
ne la considérera pas comme une autre liste, car elle contient tous les mêmes éléments , seule la commande a été modifiée.
submitList(null); submitList(orderChangedList);
Donc, pour résoudre ce problème, vous devez d'abord appeler cette fonction avec null
, puis appeler immédiatement avec la liste de modification de l'ordre.
@Override public void submitList(@Nullable final List<T> list) { super.submitList(list != null ? new ArrayList<>(list) : null); }
Oui, cela aide! Je suppose qu'il a été conçu de cette façon.
Ceci est incorrect, et pas non plus comment submitList est censé être utilisé. Le problème réel est que submitList
nécessite une nouvelle liste à soumettre, pas une référence à la même liste qui a été modifiée. Sinon, lorsque vous modifiez la liste, vous modifiez également la liste stockée par le ListAdapter et lorsque vous le soumettez, il compare la liste entrante (la même liste) et conclut que rien n'a changé. Consultez ce lien pour faire une copie de votre liste en Java ou utilisez .toList () < / code> à Kotlin
@Carson Holzheimer pouvez-vous s'il vous plaît élaborer sur cela et poster comme réponse
Cela fonctionne très bien!
Il élimine les ListAdapter but pour calculer et animer automatiquement les changements de liste lorsque vous appelez ces lignes consécutivement:
public void submitList(@Nullable List<T> list) { mDiffer.submitList(list != null ? new ArrayList<>(list) : null); }
Cela signifie que vous avez uniquement effacé ( null
) la liste actuelle de ListAdapter, puis soumis ( .submitList ()
) une nouvelle liste. Ainsi, aucune animation correspondante ne sera vue dans ce cas mais seulement une actualisation de l'ensemble de RecyclerView.
La solution consiste à implémenter la méthode .submitList (List
à l'intérieur votre ListAdapter comme suit:
submitList(null); submitList(orderChangedList);
De cette façon, vous autorisez le ListAdapter à conserver sa currentList et à le faire "différer" avec le newList, donc les animations calculées, par opposition à "diffing "avec un null
.
Remarque: Cependant, aucune animation de mise à jour ne se produira, si, bien sûr, la newList contient les mêmes éléments dans le même commander comme liste d'origine.
Cela n'aura aucun effet si les deux listes soumises ultérieurement contiennent les mêmes éléments dans un ordre différent (c'est le problème central, comme décrit dans la question initiale).
même si la liste vient d'être réorganisée, tant que vous instanciez une nouvelle arrayList en utilisant new ArrayList <> (YourReOrderedList)
dans votre ListAdapter, la différence prendra effet à moins que le processus de réorganisation ne se termine avec le même ordre que votre OriginalList.
En fait, vous avez raison. Mais deux problèmes avec cette approche sont que (pour une raison inconnue) il faut 2-3 secondes avant qu'une animation ne soit vue ET, la position de la vue de recyclage est laissée intacte (je veux qu'elle défile vers le haut après le "tri", voir ceci lié < une href = "https://stackoverflow.com/questions/55262409/recyclerview-scroll-to-top-with-asynclistdiffer-not-working"> ma question ).
La meilleure façon de revenir en haut est ici: stackoverflow.com/a/53123659/4672107
Au lieu de
newList.first().isFavourite = false
Vous devez soumettre une nouvelle liste comme celle-ci:
val newList = oldList.toList() // Unintuitive way to copy a list newList.first() = newList.first().copy(isFavourite = false) // Do whatever modifications you want submitList(newList)
C'est une sorte de problème avec l'API. Nous nous attendrions à ce que ListAdapter conserve une copie de la liste, mais ce n'est pas le cas, probablement pour des raisons de mémoire. Lorsque vous modifiez votre ancienne liste, vous modifiez en fait la même liste que ListAdapter a stockée. Lorsque ListAdapter vérifie if (newList! = This.mList)
newList
et mList
font référence à la même instance de liste, donc peu importe ce que vous avez changé dans cette liste, elle s'égalisera et ignorera votre mise à jour. p >
Dans kotlin, vous pouvez créer une nouvelle liste via:
ArrayList newList = new ArrayList(oldList); newList.add(somethingNew); // Or sort or do whatever you want submitList(newList);
Notez que vous ne pouvez pas faire ceci:
submitList(mySameOldListThatIModified)
parce que cela changera également le premier élément de votre ancienne liste, et encore une fois ListAdapter
ne verra pas de différence entre le premier élément de votre ancienne liste et le premier élément de votre nouvelle liste. Je recommanderais que tous les éléments de votre liste aient exclusivement des propriétés val
, pour éviter ce problème.
Pour ajouter à la réponse de Carson, qui est une meilleure façon de le faire, vous pouvez conserver les avantages de submitList
comme suit dans Kotlin:
submitList(oldList.toList().toMutableList().let { it[index] = it[index].copy(property = newvalue) // To update a property on an item it.add(newItem) // To add a new item it.removeAt[index] // To remove an item // and so on.... it })
Appelez simplement listAdapter.notifyDataSetChanged ()
et le ListAdapter
redessine la liste en fonction des valeurs soumises.
L'intérêt de l'utilisation d'AsyncListDiffer est de ne pas appeler notifyDataSetChanged inutilement.
@MDNaseemAshraf mais cela irait à l'encontre de l'objectif général de l'utilisation de ListAdapter. ListAdapter distribue automatiquement les modifications minimales requises à RecyclerView.
En effet. Avez-vous essayé notifyItemRangeChanged (0, List.size ()); ? Ouais, je viens de réaliser que cela aussi irait à l'encontre de l'objectif du changement minimal.
@MDNaseemAshraf connaissez-vous
ListAdapter
? Parce que je lis que nous n'avons pas besoin d'utiliser de fonctionsnotify___
avec elle car elle gère tout automatiquement.évidemment sans copie de l'ancienne liste vous n'avez rien à comparer
@Selvin, je ne suis pas sûr de comprendre.
ListAdapter
enregistre l'ancienne liste et lorsque vous appelezsubmit (newList)
, il effectue une comparaison et informe RecyclerView quels éléments ont changé.Puisque vous avez changé l'ordre de l'ensemble de données,
ListAdapter
le considérera-t-il comme un nouvel ensemble.@ PrimožKralj enregistre (fait une copie) ou garde simplement les références?
@Selvin, bon point. Voilà le problème.
Veuillez vérifier stackoverflow.com/a/53123659/6932487 au lieu de soumettre une liste nulle ou nouvelle (et perdre toute la signification du diffutils) vous devez utiliser le callback dataobserver