I. Présentation

Sous Android, le composant pour afficher une liste d'images est la Gallery. On y retrouve le même fonctionnement qu'une Listview classiquePersonnaliser une ListView : un Adapter est utilisé pour créer chacun des items de la liste. L'autre partie de ce tutoriel va vous montrer comment télécharger des ressources depuis Internet et s'en servir.

Le but étant d'arriver à un résultat proche de celui-ci :

Image non disponible

II. Création du Layout

Notre écran se veut très simple afin de cibler les deux ou trois points de ce tutoriel. Dans un LinearLayout, on va venir y placer un composant qui affichera l'image en plein écran (ImageView), ainsi qu'un composant qui affichera la liste des images (Gallery).

Layout main.xml
Sélectionnez

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_height="fill_parent"
	android:layout_width="fill_parent">

	<ImageView android:id="@+id/imageview"
		android:layout_width="fill_parent" android:src="@drawable/no_photo"
		android:layout_height="wrap_content" android:layout_weight="0.2"></ImageView>
	<Gallery android:id="@+id/gallery" android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:background="@color/blanc"></Gallery>
</LinearLayout>

III. Création de notre Activity

Notre activité va donc s'occuper d'initialiser les deux composants. Par défaut, si aucune image n'est trouvée dans la liste, l'image "no_photo" sera affichée. Cette image est placée dans le repertoire drawable de l'application. Le code sera à l'écoute de la sélection d'une image dans la galerie afin d'afficher l'image en grand dans le composant dédié :

Initialisation de l'activité
Sélectionnez

    // GUI
	private Gallery gallery;
	private ImageView imgView;

	//Data
	private ArrayList<URL> mListImages;
	private Drawable mNoImage;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		//Récupération d'une image par défaut à afficher en cas d'erreur ou de liste vide
		mNoImage = this.getResources().getDrawable(R.drawable.no_photo);

		//Construction des URL pour les images
		mListImages = buildListImages();

		//Récupération du composant affichant l'image en grand
		imgView = (ImageView)findViewById(R.id.imageview);
		
		//On lui met une image par défaut (la première de la liste ou, par défaut, l'image d'erreur)
		if (mListImages.size() <= 0) {
			imgView.setImageDrawable(mNoImage); 
		} else {
			setImage(imgView, mListImages.get(0));
		}
		//Récupération du composant affichant la liste des vignettes
		gallery = (Gallery) findViewById(R.id.gallery);
		//On lui attribue notre Adapter qui s'occupera de l'alimenter en vignettes
		gallery.setAdapter(new AddImgAdp(this));
		//Espacement entre les vignettes
		gallery.setSpacing(10);

		//Lors d'un clic sur une des vignettes, on affiche l'image correspondante en grand
		gallery.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView parent, View v, int position, long id) {			
				setImage(imgView, mListImages.get(position));
			}
		});

	}
			

Vu que la liste des images est assez longue, j'ai créé une méthode pour initialiser cette liste :

Création de la liste des images
Sélectionnez

	//Adresse  se trouve l'ensemble des images GIF (numérotées de 1 à 21).
	private final static String SERVER_IM = "http://mickael-lt.developpez.com//tutoriels/android/imagesfaq/";

    /**
	 * Permet de construire la liste des URL pour les images
	 * @return
	 */
	private ArrayList<URL> buildListImages() {
	    int nbTotalImage = 21;
		ArrayList<URL> listFic = new ArrayList<URL>();
		for(int i = 1; i <= nbTotalImage; i++) {
			try {
				listFic.add(new URL(SERVER_IM + "/" + i + ".gif"));
			} catch (MalformedURLException e) {
				Log.e("DVP Gallery", "Erreur format URL : " + SERVER_IM + "/" + i + ".gif");
				e.printStackTrace();
			}
		}

		return listFic;
	}

			

Ensuite, il nous faut créer un Adapter pour gérer l'affichage de notre Gallery. Vous noterez qu'ici les vues sont recyclées afin d'optimiser la mémoire :

Adapter pour l'affichage des vignettes
Sélectionnez

    /**
	 * Notre Adapter qui gère la liste des vignettes
	 * @author Mickaël Le Trocquer
	 */
	public class AddImgAdp extends BaseAdapter {
		int GalItemBg;
		private Context cont;

		public AddImgAdp(Context c) {
			cont = c;
			TypedArray typArray = obtainStyledAttributes(R.styleable.GalleryTheme);
			GalItemBg = typArray.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground, 0);
			typArray.recycle();
		}

		public int getCount() {
			return mListImages.size();
		}

		public Object getItem(int position) {
			return position;
		}

		public long getItemId(int position) {
			return position;
		}

		public View getView(final int position, View convertView, ViewGroup parent) {
			ImageView imgView = null;
			//Récyclage du composant
			if (convertView == null) {
				imgView = new ImageView(cont);
			} else {
				imgView = (ImageView)convertView;
			}
			//On affecte notre image à la vignette
			if (mListImages.size() <= 0) {
				imgView.setImageDrawable(mNoImage); 
			} else {
				setImage(imgView, mListImages.get(position));
			}
			//On défini la taille de l'image
			imgView.setLayoutParams(new Gallery.LayoutParams(150, 150));
			imgView.setScaleType(ImageView.ScaleType.FIT_XY);
			//On fixe un arrière plan plus sympa
			imgView.setBackgroundResource(GalItemBg);

			return imgView;
		}
	}
			

Maintenant voici le moyen de télécharger une image à partir d'une URL et de l'affecter à un composant de type ImageView :

Téléchargement d'une image et affectation à une vignette
Sélectionnez

    /**
	 * Méthode permettant de télécharger une image depuis une URL et de l'affecter à un composant de type ImageView
	 * @param aView
	 * @param aURL
	 */
	public void setImage(ImageView aView, URL aURL) {
		try {
			URLConnection conn = aURL.openConnection();
			conn.connect();
			InputStream is = conn.getInputStream();

			// Bufferisation pour le téléchargement 
			BufferedInputStream bis = new BufferedInputStream(is, 8192);

			// Création de l'image depuis le flux des données entrant
			Bitmap bm = BitmapFactory.decodeStream(bis);
			bis.close();
			is.close();

			// Fixe l'image sur le composant ImageView
			aView.setImageBitmap(bm);
		
		} catch (IOException e) {
			aView.setImageDrawable(mNoImage);
			Log.e("DVP Gallery", "Erreur téléchargement image URL : " + aURL.toString());
			e.printStackTrace();
		} 
	}
			

Vu qu'on souhaite télécharger des fichiers depuis Internet, je vous conseille de rajouter l'autorisation dans votre manifest.xml :

manifest.xml
Sélectionnez

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.dvp.android.gallery"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".DVPGallery"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    <uses-sdk android:minSdkVersion="4" />
    
	<uses-permission android:name="android.permission.INTERNET"></uses-permission>


</manifest> 
			

IV. Conclusion

Pour conclure, le composant Gallery se gère comme un composant ListView dans son utilisation basique. D'autres paramètres permettent de personnaliser ce composant (espacement entre les items, zoom à appliquer sur l'item ayant le focus, etc). Le téléchargement de ressources sur Internet n'est pas vraiment un problème ici. Le seul point bloquant c'est les temps d'attente pour les téléchargements. Les sources de cette application sont téléchargeables ici : DVP_Gallery.zip
Cet article traite d'un cas simple, pour bien finaliser cet exemple, il faudrait introduire la notion de Thread, d'optimisation pour le téléchargement, etc. Vous pouvez trouver un exemple complet ici : MultiThreading sur android-developersMultiThreading sur android-developers

V. Remerciements

Je voudrais remercier Benjamin POINSOT pour sa contribution et ses corrections.

VI. Liens