Créer une galerie connectée

| Mickaël Le Trocquer | Mickael_LT |

Cet article va vous permettre de comprendre comment fonctionne le composant 'Gallery', mais également comment réaliser des appels serveur afin de télécharger des images, puis les afficher.

Commentez ♪

- Titre : Créer une galerie connectée

- Auteurs : Mickaël Le Trocquer, Mickael_LT

- Parution : 24 novembre 2010

- Licence : Copyright ® 2010 Mickaël Le Trocquer. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Présentation

- II. Création du Layout

- III. Création de notre Activity

- IV. Conclusion

- V. Remerciements

- VI. Liens

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 classique : 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 :

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

<?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 répertoire 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é

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

//Adresse où 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

/**
* 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

/**
* 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

<?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-developers

V - Remerciements

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

VI - Liens

Site du développeur
FAQ Android
Installation de l'environnement
Création d'un carrousel
MultiThreading sur android-developers