Aller au contenu

Chargement des éléments d'une ListView


RudyBSD

Recommended Posts

Bonjour.

Comme beaucoup, mon application a besoin de charger des images accompagnées de texte dans une ListView depuis internet.

Cela fonctionne cependant je rencontre un problème :

Ma ListView contient plus d'éléments qu'il ne peut en être affiché, ainsi, lorsque je scroll pour afficher des éléments plus bas dans la liste, les images de ceux-ci ne chargent pas (Seul le texte l'est et l'image reste celle que j'ai définie par défaut).

Le chargement des items de la ListView se fait dans un thread durant lequel j'affiche une PorgressDialog. Le chargement des images est également effectué dans un thread qui est lancé par le thread de chargement des items.

Je me demandais également comment faire pour éviter que la ListView ne se remette en « position 0 » (revenir à afficher les premiers éléments) lorsque chaque image est chargée.

[Edit] Solution trouvée :

- utilisation d'une Hashtable pour mémoriser les caractéristiques des objets à afficher.

- utilisation d'un SimpleAdapter et de ViewBinder pour peupler les items de la liste lors du chargement des images.

[/Edit]

Par avance merci,

Rudy.

Lien vers le commentaire
Partager sur d’autres sites

Je te conseille d'insérer

e.printStackTrace();

dans le catch de tes exception, ça t'informera si une exception est levée.

d'autre part, pour alléger ton code je te conseille de créer une méthode qui se chargera de créer ton taost en prenant une String et un contexte en paramètre par exemple.

Un autre conseil pour l'indentation si tu es sous Eclipse un petit Ctrl+shift+f devrait te simplifier la vie !

Ensuite je ne comprends pas cette ligne

 sAdapter.setViewBinder(new MyViewBinder());

Je ne suis pas un spécialiste des ListView !

Dernier point, quand tu fais ta récupération d'objet JSON, à chaque récupération tu appelles displayUI et ensuite ajoute ton objet à ta liste mais dans display UI tu parcours toute ta liste, il n'y a pas de risque de parcourir trop de fois ta liste videos ?

Lien vers le commentaire
Partager sur d’autres sites

Merci pour ta réponse.

Je viens de mettre en application tes conseils :

- J'ai ajouté une méthode pour l'affichage des Toasts. Ma méthode était bien moche.

- J'ai ajouté les e.printStackTrace(); pour les levées d'exceptions.

- Ta remarque était tout à fait juste pour le parcours de ma liste de vidéos. J'ai donc créé une méthode updateUI(int position, Videos video); qui ne modifie que la vidéo concernée.

- Très pratique le Ctrl-Shift-f en effet. Je n'en suis qu'à ma toute première application Android (et programme Java digne de ce nom par la même occasion), je ne suis donc pas encore bien familiarisé avec Eclipse. (Et avec les IDE en général, habitué au C, je code habituellement avec vim et gcc ... On en est loin ici :)).

Pour ce qui est de :

 sAdapter.setViewBinder(new MyViewBinder());

Cette ligne sert à indiquer mon ViewBinder qui servira à mettre les images de mes items étant donné que je ne peux pas faire de monImageView.setImageBitmap(monImageBmp); pour les items de ma ListView. C'est du moins la solution que j'ai trouvé, il y a sûrement mieux.

Tout ceci effectué, cela ne règle toujours pas mon problème. Les images des items non affichés de ma ListView ne sont pas chargées lorsque ceux-ci deviennent visible.

Encore merci cependant pour tes conseils avisés Mc Flurry.

Voici le code de ma fonction updateUI(int, Videos); :

	public void updateUI(int position, Videos video) {
	ListView lv = (ListView) this.findViewById(40);
	HashMap<String, Object> map = new HashMap<String, Object>();
	map.put("img", video.getImg());
	map.put("guest", video.getGuest());
	map.put("descr", video.getDescr());
	listItem.set(position, map);

	sAdapter = new SimpleAdapter(this.getBaseContext(), listItem,
			R.layout.items, new String[] { "img", "guest", "descr" },
			new int[] { R.id.img, R.id.guest, R.id.descr });
	sAdapter.setViewBinder(new MyViewBinder());
	lv.setAdapter(sAdapter);
}

J'appelle cette méthode de la manière suivante (en lieu et place de l'ancien appel à displayUI() dans mon Thread pour le chargement des images) :

/* ... */
			_vid.setImg(itl.loadImage((String) json_data.get("img"),
					new ImageLoadedListener() {
						public void imageLoaded(Bitmap image) {
							_vid.setImg(image);
							updateUI(videos.indexOf(_vid), _vid);
						}
					}));
/* ... */

Lien vers le commentaire
Partager sur d’autres sites

Y'a pas de quoi, ce forum est fait aussi pour ça ;)

Pour ce qui est de :

sAdapter.setViewBinder(new MyViewBinder());

Cette ligne sert à indiquer mon ViewBinder qui servira à mettre les images de mes items étant donné que je ne peux pas faire de monImageView.setImageBitmap(monImageBmp); pour les items de ma ListView. C'est du moins la solution que j'ai trouvé, il y a sûrement mieux.

J'ai bien compris ce que tu voulais faire, mais en seulement créant un objet MyViewBinder, tu n'appliques en aucun cas la méthode setImageBitmap puisqu'elle n'est jamais invoquée...

Pour faire ce que tu veux, utilise plutôt un constructeur.

C'est normal que tu galère avec Eclipse, au début c'est toujours comme ça, mais c'est franchement un plus pour la programmation JAVA ou Android.

Lien vers le commentaire
Partager sur d’autres sites

C'est mon ViewBinder qui sert à peupler les images de mes items lorsque celles-ci sont chargées :

        public class MyViewBinder implements ViewBinder {
               @Override
               public boolean setViewValue(View view, Object data, String textRepresentation) {
                       if((view instanceof ImageView) & (data instanceof Bitmap)) {
                               ImageView iv = (ImageView)view;
                               Bitmap bm = (Bitmap)data;
                               iv.setImageBitmap(bm);
                               return true;
                       }
                       return false;
               }
       }

Ainsi mon SimpleAdapter sAdapter utilise comme ViewBinder un MyViewBinder pour peupler mes items. (voir : la doc ici et ).

Je viens de régler mon problème de chargement d'image qui ramène la ListView en position initiale en replacant :

                sAdapter = new SimpleAdapter(this.getBaseContext(), listItem,
                               R.layout.items, new String[] { "img", "guest", "descr" },
                               new int[] { R.id.img, R.id.guest, R.id.descr });
               sAdapter.setViewBinder(new MyViewBinder());
               lv.setAdapter(sAdapter);

par

sAdapter.notifyDataSetChanged();

dans ma méthode updateUI.

Me reste plus que le problème de chargement d'image pour les items « cachés ».

Pour ce qui est d'éclipse, en effet, c'est un peu la galère au début là ... En utilisant cet IDE, j'ai un peu l'impression d'utiliser un bazooka pour détruire un moucheron. C'est assez gros et très fourni en fonctionnalités pour le peu de trucs dont j'ai besoin pour développer une application. Après, ça vient peut être aussi du fait que je sois habitué à un environnement disons ... minimaliste :).

Lien vers le commentaire
Partager sur d’autres sites

J'ai débuté sous NotePad++ avec le terminal de commandes alors Eclipse a été pour moi aussi une révolution !

Je t'avoue que j'ai très peu utilisé le système d'adapter, seulement pour des événement souris simple donc j'ai peu de recul vis à vis de ça, il faudrait l'avis d'un connaisseur :P

J'ai compris ton système d'héritage de ViewBinder, mais quand est comment ta méthode setViewBinder est elle appelée ?

Je pense que ton problème viens de la, tes objets sont bien créés et ajoutés à ta liste

sAdapter.setViewBinder(new MyViewBinder());
               lv.setAdapter(sAdapter);

Seulement du fait de

new MyViewBinder()

Tes objets sont vide car tu appel le constructeur vide par défaut et celui ci ne fait aucune opération spéciale, il place juste les attributs à null.

Pour tester si ce que je dis est vrai remplace ta boucle de parcours de videos par celle ci :

 for (Videos video:videos) {
               map = new HashMap<String, Object>();
               bmp = video.getImg();
               if (bmp == null){
                       map.put("img", R.drawable.icon);
Log.d("json_test", "..:: L'image "+bmp.toString()+" n'a pas été modifiée ::..");
}
               else{
                       map.put("img", bmp);
Log.d("json_test", "..:: L'image "+bmp.toString()+" est bien configurée ::..");
}
               try {
                       map.put("descr", video.getDescr());
               }catch(Exception e) {
                       Context context = getApplicationContext();
               CharSequence text = "map.put : "+e.toString();
               int duration = Toast.LENGTH_LONG;
               Toast toast = Toast.makeText(context, text, duration);
               toast.show();
               }
                       map.put("guest", video.getGuest());
               listItem.add(map);
       }

Tu devrais voir apparaitre dans le LogCat plusieurs messages t'indiquant l'état de ton image lors de l'ajout à la ListView.

Derniere petite remarque, je suis pointilleux dis donc :P , le nom d'une classe en Java commence toujours par une majuscule, c'est une convention. Eclipse à du te le signalé d'ailleurs ;)

Edit : Ha oui, tu devrais faire les import nécessaire pour utiliser le Log.

Lien vers le commentaire
Partager sur d’autres sites

Ma fonction displayUI() étant appelée avant que les images ne soient chargées, bmp sera forcément égal à null. J'ai oublié de retirer cette partie en ne laissant que : map.put("img", R.drawable.icon);.

La condition était utile lorsque je rappelais displayUI() après chargement d'une image mais maintenant c'est inutile étant donné que c'est updateUI(int, Video) qui est appelée. Désolé pour cet oubli.

J'ai changé mes HashMap en Hashtable, j'ai lu que les HashMap était déconseillées lorsqu'elles sont utilisées avec des Threads car celles-ci ne sont pas synchronisées ce qui peut poser problème en cas d'opérations concurrentes. Cela a résolu mon problème.

Tout fonctionne maintenant comme je le voulais. Ma ListeView ne bouge pas lors du chargement des images et l'ensemble des images sont chargées comme il le faut.

Pour ce qui est des noms de classes, j'ai encore un peu de mal avec les conventions de nommage de Java. Merci :).

Merci beaucoup Mc Flurry pour tes conseils qui m'ont permis de regarder mon code avec un œil plus avisé et donc d'être plus efficace dans la recherche de mes erreurs.

Si quelqu'un ayant eu le même problème que moi tombe sur ce sujet, voici ma méthode :

- utilisation d'une Hashtable pour mémoriser les caractéristiques des objets à afficher.

- utilisation d'un SimpleAdapter et de ViewBinder pour peupler les items de la liste lors du chargement des images.

Lien vers le commentaire
Partager sur d’autres sites

Ah en fait non ça va pas !

Je sais pas pourquoi mais là, sans rien toucher, bah ça marche plus ...

Les images des items non affichés au départ se chargent certaines fois, et d'autres non ... Allez comprendre ...

De plus, j'utilise :

		lv.setOnScrollListener(new OnScrollListener() {

		@Override
		public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
			// TODO Auto-generated method stub
			if (sAdapter != null)
				sAdapter.notifyDataSetChanged();
		}

		@Override
		public void onScrollStateChanged(AbsListView arg0, int arg1) {
			sAdapter.notifyDataSetChanged();
		}

	});

Pour être sur de l'affichage des nouvelles images lors du scroll de la ListView mais en faisant cela je ne peux désormais plus sélectionner d'item ... (j'avais pas fais gaffe, j'étais focaliser sur l'apparition des images ...).

Je comprend pas du coup ...

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...