J'ai un ListView
qui affiche des actualités. Ils contiennent une image, un titre et du texte. L'image est chargée dans un fil séparé (avec une file d'attente et tout) et lorsque l'image est téléchargée, j'appelle maintenant notifyDataSetChanged()
l'adaptateur de liste pour mettre à jour l'image. Cela fonctionne, mais getView()
est appelé trop fréquemment, car il notifyDataSetChanged()
appelle getView()
tous les éléments visibles. Je souhaite mettre à jour uniquement l'élément unique de la liste. Comment ferais-je cela?
Les problèmes que j'ai avec mon approche actuelle sont:
- Le défilement est lent
- J'ai une animation de fondu sur l'image qui se produit chaque fois qu'une seule nouvelle image dans la liste est chargée.
Cette question a été posée lors du Google I / O 2010, vous pouvez la regarder ici:
Le monde de ListView, heure 52:30
En gros, ce que Romain Guy explique, c'est de faire appel
getChildAt(int)
auListView
pour avoir la vue et (je pense) appelergetFirstVisiblePosition()
pour connaître la corrélation entre la position et l'indice.Romain cite également le projet nommé Shelves comme exemple, je pense qu'il peut vouloir dire la méthode
ShelvesActivity.updateBookCovers()
, mais je ne trouve pas l'appelgetFirstVisiblePosition()
.MISES À JOUR IMPRESSIONNANTES À VENIR:
Le RecyclerView résoudra ce problème dans un proche avenir. Comme indiqué sur http://www.grokkingandroid.com/first-glance-androids-recyclerview/ , vous pourrez appeler des méthodes pour spécifier exactement le changement, telles que:
De plus, tout le monde voudra utiliser les nouvelles vues basées sur RecyclerView car ils seront récompensés par de jolies animations! L'avenir semble génial! :-)
la source
Voici comment je l'ai fait:
Vos éléments (lignes) doivent avoir des identifiants uniques afin que vous puissiez les mettre à jour ultérieurement. Définissez la balise de chaque vue lorsque la liste obtient la vue de l'adaptateur. (Vous pouvez également utiliser la balise clé si la balise par défaut est utilisée ailleurs)
Pour la mise à jour, vérifiez chaque élément de la liste, si une vue avec un identifiant donné est là, elle est visible, nous effectuons la mise à jour.
C'est en fait plus facile que d'autres méthodes et mieux lorsque vous traitez avec des identifiants et non des positions! Vous devez également appeler update pour les éléments qui deviennent visibles.
la source
obtenir la classe de modèle d'abord comme globale comme cet objet de classe de modèle
et initialisez-le à global
obtenir la ligne courante de la vue par le modèle en l'initialisant au modèle global
définissez la valeur modifiée sur la méthode d'objet de modèle global à définir et ajoutez le notifyDataSetChanged qui fonctionne pour moi
Voici une question connexe à ce sujet avec de bonnes réponses.
la source
Les réponses sont claires et correctes, je vais ajouter une idée de
CursorAdapter
cas ici.Si vous êtes en sous-classement
CursorAdapter
(ouResourceCursorAdapter
, ouSimpleCursorAdapter
), alors vous pouvez implémenterViewBinder
ou remplacerbindView()
et desnewView()
méthodes, celles-ci ne reçoivent pas l'index d'élément de liste actuel dans les arguments. Par conséquent, lorsque certaines données arrivent et que vous souhaitez mettre à jour des éléments de liste visibles pertinents, comment connaître leurs indices?Ma solution était de:
newView()
notifyDatasetChanged()
et de les actualiser toutesEn raison du recyclage des vues, le nombre de références de vues que je devrai stocker et itérer sera à peu près égal au nombre d'éléments de liste visibles à l'écran.
la source
Pour RecycleView, veuillez utiliser ce code
la source
J'ai utilisé le code qui a fourni Erik, fonctionne très bien, mais j'ai un adaptateur personnalisé complexe pour ma liste et j'ai été confronté à deux fois la mise en œuvre du code qui met à jour l'interface utilisateur. J'ai essayé d'obtenir la nouvelle vue de la méthode getView de mes adaptateurs (l'arraylist qui contient les données de listview a déjà été mise à jour / modifiée):
Cela fonctionne bien, mais je ne sais pas si c'est une bonne pratique. Je n'ai donc pas besoin d'implémenter le code qui met à jour l'élément de liste deux fois.
la source
exactement je l'ai utilisé
la source
J'ai inventé une autre solution, comme la méthode RecyclyerView void
notifyItemChanged(int position)
, créez la classe CustomBaseAdapter comme ceci:N'oubliez pas de créer également une classe CustomDataSetObservable pour la
mDataSetObservable
variable dans CustomAdapterClass , comme ceci:sur la classe CustomBaseAdapter, il existe une méthode
notifyItemChanged(int position)
, et vous pouvez appeler cette méthode lorsque vous souhaitez mettre à jour une ligne où vous le souhaitez (à partir d'un clic sur le bouton ou à n'importe quel endroit où vous voulez appeler cette méthode). Et voila !, votre seule ligne sera mise à jour instantanément.la source
Ma solution: si elle est correcte *, mettez à jour les données et les éléments visibles sans redessiner la liste entière. Sinon notifierDataSetChanged.
Correct - oldData size == nouvelle taille de données, et anciens ID de données et leur ordre == nouveaux ID de données et ordre
Comment:
et bien sûr:
Ignorez le dernier paramètre de bindView (je l'utilise pour déterminer si je dois recycler les bitmaps pour ImageDrawable).
Comme mentionné ci-dessus, le nombre total de vues `` visibles '' est à peu près la quantité qui tient sur l'écran (en ignorant les changements d'orientation, etc.), donc pas de gros problèmes de mémoire.
la source
En plus de cette solution ( https://stackoverflow.com/a/3727813/5218712 ) je veux juste ajouter qu'elle ne devrait fonctionner que s'il
listView.getChildCount() == yourDataList.size();
pourrait y avoir une vue supplémentaire dans ListView.Exemple de remplissage des éléments enfants:
la source