136 votes

Comment puis-je mettre à jour une seule ligne dans une ListView ?

J'ai un ListView qui affiche les articles d'actualités. Ils contiennent une image, un titre et du texte. L'image est chargée dans un thread séparé (avec une file d'attente et tout et tout) et lorsque l'image est téléchargé, je vais maintenant appeler notifyDataSetChanged() sur la liste de l'adaptateur pour mettre à jour l'image. Cela fonctionne, mais getView() est appelé trop souvent, depuis notifyDataSetChanged() des appels getView() pour tous les éléments visibles. Je veux mettre à jour seulement le seul élément dans la liste. Comment puis-je faire?

Les problèmes que j'ai avec mon approche actuelle sont:

  1. Le défilement est lent
  2. J'ai fondu en animation sur l'image qui se produit chaque fois qu'une nouvelle image dans la liste est chargé.

200voto

Erik Points 2065

J’ai trouvé la réponse, grâce à vos informations de Michelle. Vous pouvez en effet obtenir la vue droite à l’aide de vue #getChildAt(int index). Le hic, c’est qu’il commence à compter du premier élément visible. En fait, vous pouvez uniquement obtenir les éléments visibles. Vous résoudre ce problème avec ListView#getFirstVisiblePosition().

Exemple :

72voto

mreichelt Points 6217

Cette question a été posée lors de la Google I/O 2010, vous pouvez le visionner ici:

Le monde de la ListView, fois 52:30

Fondamentalement, ce que Romain Guy explique est d'appeler getChildAt(int) sur le ListView pour obtenir la vue et (je crois), appel getFirstVisiblePosition() de trouver la corrélation entre la position et l'index.

Romain souligne également le projet appelé Étagères comme un exemple, je pense qu'il pourrait signifier la méthode ShelvesActivity.updateBookCovers(), mais je ne trouve pas à l'appel de l' getFirstVisiblePosition().

GÉNIAL MISES À JOUR À VENIR:

Le RecyclerView vais corriger cela dans un avenir proche. Comme l'a souligné sur http://www.grokkingandroid.com/first-glance-androids-recyclerview/, vous serez en mesure d'appeler les méthodes de spécifier exactement le changement, tels que:

void notifyItemInserted(int position)
void notifyItemRemoved(int position)
void notifyItemChanged(int position)

Aussi, tout le monde va vouloir utiliser les nouvelles vues basées sur RecyclerView parce qu'ils seront récompensés avec bien-à la recherche d'animations! L'avenir s'annonce génial! :-)

6voto

Ali Points 1597

Voilà comment j'ai fait:

Vos éléments (lignes) doit avoir les identifiants uniques de sorte que vous pouvez les mettre à jour plus tard. Définir la balise de chaque vue lorsque la liste est d'obtenir le point de vue de l'adaptateur. (Vous pouvez également utiliser la touche si la balise la balise par défaut est utilisé ailleurs)

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    View view = super.getView(position, convertView, parent);
    view.setTag(getItemId(position));
    return view;
}

Pour la vérification de mise à jour à chaque élément de la liste, si d'un point de vue avec des id donné est-il qu'il est visible de sorte que nous effectuer la mise à jour.

private void update(long id)
{

    int c = list.getChildCount();
    for (int i = 0; i < c; i++)
    {
        View view = list.getChildAt(i);
        if ((Long)view.getTag() == id)
        {
            // update view
        }
    }
}

Il est effectivement plus facile que les autres méthodes et mieux lorsque vous traitez avec des id de ne pas les postes! Aussi, vous devez appeler la mise à jour pour les éléments qui deviennent visibles.

2voto

Pēteris Caune Points 13662

Les réponses sont claires et précises, je vais ajouter une idée pour CursorAdapter cas ici.

Si vous êtes à la sous-classement CursorAdapter (ou ResourceCursorAdapterou SimpleCursorAdapter), puis vous arrivez à la mise en œuvre ViewBinder ou remplacer bindView() et newView() méthodes, ce n'est pas le recevoir courant de la liste d'index de l'élément dans les arguments. Par conséquent, lorsque certaines données arrive et vous souhaitez mettre à jour pertinentes visible les éléments de la liste, comment savez-vous de leurs indices?

Ma solution a été de:

  • conservez une liste de tous créé élément de la liste de vues, d'ajouter des éléments à cette liste à partir d' newView()
  • lorsque les données arrivent, les réitérer et de voir celui qui doit être mis à jour--mieux que de faire de l' notifyDatasetChanged() et rafraîchissante tous

En raison de la vue du recyclage le nombre d'afficher les références, je vais avoir besoin de stocker et itérer sera à peu près égal au nombre d'éléments de la liste visible sur l'écran.

1voto

Primoz990 Points 470

J'ai utilisé le code fourni Erik, fonctionne très bien, mais j'ai un complexe adaptateur personnalisé pour mon listview et j'ai été confronté à deux fois la mise en œuvre du code de mises à jour de l'INTERFACE utilisateur. J'ai essayé d'obtenir la nouvelle vue de mes adaptateurs méthode getView(arraylist qui contient la liste des données a déjà été mis à jour/modifiés):

View cell = lvOptim.getChildAt(index - lvOptim.getFirstVisiblePosition());
if(cell!=null){
    cell = adapter.getView(index, cell, lvOptim); //public View getView(final int position, View convertView, ViewGroup parent)
    cell.startAnimation(animationLeftIn());
}

Il fonctionne bien, mais je ne sais pas si c'est une bonne pratique. Je n'ai pas besoin de mettre en œuvre le code qui met à jour l'élément de liste à deux reprises.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X