Aller au contenu

holder ListView


l-amoureu

Recommended Posts

Bonjour

Je développe une appli, et j'ai besoin de me servir d'une listView.

La listView contient X item, chaque item contient une imageView (a gauche) et trois textView (a droite)

Jusque là, j'ai pas de soucis majeur.

Le soucis bien du fait que chaque item utilise une image téléchargé sur internet, et ca met relativement longtemps a télécharger.

J'avais donc pensé a threader la partis téléchargement, a mettre une image de base a chaque item en attendant que le téléchargement soit fini, et lorsque qu'il est fini, a associer les imageView aux images.

Mais avant ca, j'ai dois résoudre un problème.

En effet, au départ, le téléchargement se faisait au niveau de l'adapter (dans le getView), mais il y avait duplication des image.

J'ai donc suivis certains conseil, mais maintenant, je m'aperçois que chaque image est téléchargé plein de fois (ce que je ne comprend pas), et le défilement de la listView lag beaucoup.

J'ai essayé de rajouter dans mon holder un champs Bitmap, de lui associé une fois pour toute l'image télécharger, et de faire holder.image.setImageBitmap(monImage), mais sans succés.

Je vous met la partis de code concerné (avec ce code, j'ai une duplication de certaines images)

	public static class ViewHolder {
	ImageView image;
	TextView nom;
	TextView appellation;
	TextView prix;
	Bitmap mImage;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
	ViewHolder holder = null;
	Bitmap image;

	if (convertView == null)
	{
		convertView = myInflater.inflate(R.layout.item_vin, null);
		holder = new ViewHolder();
		holder.image = (ImageView) convertView.findViewById(R.id.imagePetiteDuVin);
		holder.nom = (TextView) convertView.findViewById(R.id.nomDuChateau);
		holder.appellation = (TextView) convertView.findViewById(R.id.appellationDuVin);
		holder.prix = (TextView) convertView.findViewById(R.id.prixDuVins);

		String mImage = vins.get(position).url_small;
		image = telechargerImage(mImage);
		holder.mImage = image;
//			holder.image.setImageBitmap(image);

		convertView.setTag(holder);
	} else {
		holder = (ViewHolder) convertView.getTag();
		image = holder.mImage;
	}

	holder.image.setImageBitmap(image);
	holder.nom.setText(vins.get(position).nom);
	holder.appellation.setText(vins.get(position).appellation);
	holder.prix.setText("Prix : "+vins.get(position).prix);

	return convertView;
}

Cordialement

Lien vers le commentaire
Partager sur d’autres sites

Une ListView n'instancie pas autant de View (correspondant à une ligne de la liste) qu'il y a d'éléments dans la liste. Mais, question d'optimisation, elle recycle les vues qui ne sont plus utilisées; ainsi, lorsque tu scrolles ta liste vers le bas, la View correspondant à l'élément qui disparait en haut de la liste sera réutilisée pour afficher le prochain élément qui apparaîtra en bas.

Tu ne peux donc pas stocker une information spécifique à une ligne de ta liste dans la View, cette View étant affectée potentiellement au fil du temps à plusieurs lignes différentes.

Dans ton cas, il faut que tu stockes l'image téléchargée dans l'élément géré par la liste (réprésentée par l'Adapter)

Lien vers le commentaire
Partager sur d’autres sites

Bon, je suis partis sur une autre facon de faire.

J'ai décidé de creer un ArrayList<Bitmap> en global (global au niveau de ma class adapter)

Et, ce que je fais, c'est qu'une fois que j'ai téléchargé mon image, je l'enregistre a l'index "position".

Ca fonctionne pour les 6 premiere (car elles sont directement chargé)

Donc, ce que j'ai fais, c'est que les suivante seront chargé lorsque l'on descendra la liste, mais ca fonctionne toujours pas.

Une idée ?

	@Override
public View getView(int position, View convertView, ViewGroup parent) {
	ViewHolder holder = null;
	Bitmap image;

	if (convertView == null)
	{
		convertView = myInflater.inflate(R.layout.item_vin, null);
		holder = new ViewHolder();
		holder.image = (ImageView) convertView.findViewById(R.id.imagePetiteDuVin);
		holder.nom = (TextView) convertView.findViewById(R.id.nomDuChateau);
		holder.appellation = (TextView) convertView.findViewById(R.id.appellationDuVin);
		holder.prix = (TextView) convertView.findViewById(R.id.prixDuVins);

		String mImage = vins.get(position).url_small;
		image = telechargerImage(mImage);
		bitmaps.add(image);

		convertView.setTag(holder);
	} else {
		holder = (ViewHolder) convertView.getTag();
	}
	if(position >= bitmaps.size()){
		String mImage = vins.get(position).url_small;
		image = telechargerImage(mImage);
		bitmaps.add(image);
	}

	try {
		holder.image.setImageBitmap(bitmaps.get(position));
		holder.nom.setText(vins.get(position).nom);
		holder.appellation.setText(vins.get(position).appellation);
		holder.prix.setText("Prix : "+vins.get(position).prix);
	} catch (Exception e) {
		e.printStackTrace();
	}

	return convertView;
}

Je pense que l'idée est bonne, non ? Ca me permet d'éviter de télécharger sans cesse les image, et je peux y accéder n'importe quand (en théorie).

Lien vers le commentaire
Partager sur d’autres sites

L'idée est là, c'est ce que j'aurais proposé. A une nuance près. Je n'aurais pas utilisé une ArrayList, plutôt une Map en indexant sur l'URI de ton image. Je ne suis pas sûr que tous les éléments intermédiaires de ta liste soient affichés lors d'un scroll rapide de la ListView. Et tu pourrais donc avoir une désynchro

Je te conseillerai donc plutôt cela:

   private Map<String,Bitmap> bitmaps = new HashMap<String,Bitmap>();

puis l'utilisation:

        @Override
       public View getView(int position, View convertView, ViewGroup parent) {
               ViewHolder holder = null;
               Bitmap image;

               if (convertView == null)
               {
                       convertView = myInflater.inflate(R.layout.item_vin, null);
                       holder = new ViewHolder();
                       holder.image = (ImageView) convertView.findViewById(R.id.imagePetiteDuVin);
                       holder.nom = (TextView) convertView.findViewById(R.id.nomDuChateau);
                       holder.appellation = (TextView) convertView.findViewById(R.id.appellationDuVin);
                       holder.prix = (TextView) convertView.findViewById(R.id.prixDuVins);

                       convertView.setTag(holder);
               } else {
                       holder = (ViewHolder) convertView.getTag();
               }

               try {
                       String mImage = vins.get(position).url_small;
                       if (!bitmaps.containsKey(mImage))
                       {
                           image = telechargerImage(mImage);
                           bitmaps.put(mImage, image);
                       }
                       holder.image.setImageBitmap(bitmaps.get(mImage));
                       holder.nom.setText(vins.get(position).nom);
                       holder.appellation.setText(vins.get(position).appellation);
                       holder.prix.setText("Prix : "+vins.get(position).prix);
               } catch (Exception e) {
                       e.printStackTrace();
               }

               return convertView;
       }

Après, il faudrait pousser la réflexion un peu plus loin:

- déporter le chargement des images dans un thread (actuellement, il est fait dans le thread UI, ce qui doit provoquer les lags dont tu parles),

- gérer la consommation mémoire, en limitant le nombre d'images chargés (gestion de cache)

- ...

Lien vers le commentaire
Partager sur d’autres sites

Merci beaucoup pour ton aide, ca fonctionne maintenant :)

Juste, si ca ne t'embête pas, pourrais tu m'expliquer (rapidement) pourquoi est ce que ca ne fonctionnais pas totalement avec l'ArrayList, alors que ca fonctionne avec la Map ?

Lien vers le commentaire
Partager sur d’autres sites

Je ne saurais totalement expliquer pourquoi ça ne marchait pas avec la List. J'y voyais d'abord un gros problème, c'est que une image était systématiquement ajoutée en dernière position, ce qui présupposait que la méthode getView était appelée dans l'ordre précis des éléments, et rien ne te le garantit

A partir de là, la solution par Map me paraissait plus déterministe

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...