© JMF (Tous droits réservés) 1

Chapitre 3 bis
Les interfaces utilisateurs
avancés avec Android
© JMF (Tous droits réservés) 2
Les IHM des smartphones
en 2012

Pas seulement clavier écran

Mais écran tactile

Accéléromètre

GPS

Enregistrement de messages audio (notes audio)

Prendre des photos, des vidéos, les envoyer par le
réseau (MMS)

SMS

Téléphone
© JMF (Tous droits réservés) 3
Révision de lépisode
précédent

En Android, on construit les !M plut"t avec un #ichier $M% rangé dans
res\layout mon_ihm.xml contenant par e&emple '

(e #ichier est repéré dans le code )ava par R.layout.nomBaseFichier
et on positionne l*!M de l*activité + l*aide de ce #ichier par
setContentView(R.layout.nomBaseFichier);

,n récupère un composant graphi-ue particulier de l*!M par la méthode
.miracle. findViewById(R.id.idDuComposant)/

0emar-ue ' les R. sont des int -ui ont été généré par l*environnement
dans le #ichier R.java
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ...
<TextView
...
android:id="@+id/text1" />
setContentView(R.layout.mon_ihm);
TextView tx = (TextView) findViewById(R.id.text1);
© JMF (Tous droits réservés) 4
!aille " différence entre p#$
dp$ dip$ sp %1&3'

p& ' Pi&els 1 corresponds to actual pi&els on the screen

in ' nches 1 2ased on the physical si3e o# the screen

mm ' Millimeters 1 2ased on the physical si3e o# the screen

pt ' Points 1 4567 o# an inch 2ased on the physical si3e o# the screen

source '
http://stackoverflow.com/questions/2025282/differe
nce-of-px-dp-dip-and-sp-in-android
© JMF (Tous droits réservés) 5
!aille " différence entre p#$
dp$ dip$ sp %2&3'

dp ' 8ensity1independent Pi&els 1 an a2stract unit that is 2ased on the
physical density o# the screen9 These units are relative to a 4:; dpi screen,
so one dp is one pi&el on a 4:; dpi screen9 The ratio o# dp1to1pi&el <ill
change <ith the screen density, 2ut not necessarily in direct proportion9
=ote' The compiler accepts 2oth .dip. and .dp., though .dp. is more
consistent <ith .sp.

En #ait en général dp > (resolution en dpi54:;) p& 9 Sur un écran de
résolution de 4:; dpi, dp > p& mais si la résolution est ?7; dpi, on a plut"t
4 dp > 7 pi&els

(onclusion /' e&pression en dp >@ le système convertit cette unité en pi&els
physi-ues >@ l*image aura la mAme taille -uel -ue soit l*écran

source '
http://stackoverflow.com/questions/11667907/android-
emulator-failed-to-allocate-memory-8/11868277#11868277
© JMF (Tous droits réservés) 6
!aille " différence entre p#$
dp$ dip$ sp %3&3'

sp ' Scale1independent Pi&els 1 this is liBe the dp unit, 2ut it is also
scaled 2y the user*s #ont si3e pre#erence9 t is recommend you use
this unit <hen speci#ying #ont si3es, so they <ill 2e adCusted #or 2oth
the screen density and user*s pre#erences

source '
http://stackoverflow.com/questions/2025282/differe
nce-of-px-dp-dip-and-sp-in-android
© JMF (Tous droits réservés) 7
Les bouton radios

A l*intérieur d*une 2oite de regroupement ' le RadioGroup

Dn android.widget.RadioGroup est un ViewGroup

est, par e&emple, codé par '
<RadioGroup
android:id="@+id/rgGroup1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RadioButton android:id="@+id/RB1" android:text="Button1" />
<RadioButton android:id="@+id/RB2" android:text="Button2" />
<RadioButton android:id="@+id/RB3" android:text="Button3" />
</RadioGroup>
© JMF (Tous droits réservés) 8
(estion des événements
sur les bouton radios

(*est similaire au& 2outons .poussoirs.

Avec le code précédent '
...
rb1 = (RadioButton) findViewById(R.id.RB1);
...
rb1.setOnClickListener(new RadioGroup.OnClickListener() {
public void onClick(View v){
// code lancé lorsque l'utilisateur sélectionne
// le premier bouton radio
}
});
© JMF (Tous droits réservés) 9
)t*les et !h+mes

Dn style est un ensem2le de propriétés précisant l*aspect de
composants graphi-ues (View)

l est dé#ini dans un #ichier $M% séparé de l*!M

(ette notion est similaire au (SS ((ascading StyleSheets) pour le
<e2 avec la mAme philosophie ' séparer le contenu de l*aspect

8e mAme -ue pour les (SS, ces in#ormations de style sont
hiérarchisées

Dn thème est un style pour une Activity

Dne activity ayant un thème associé transmets les indications du
thème + toutes les View contenus dans l*activité

source '
developper.android.com/docs/guide/topics/ui/themes.html
© JMF (Tous droits réservés) 10
)éparer contenu et aspect
avec les st*les

Au lieu d*écrire
on écrira plut"t
et les in#ormations de style sont repérées par l*identi#icateur
CodeFont

CodeFont est en #ait une entrée (i9e9 un élement $M%) dans un
#ichier de style
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#00FF00"
android:typeface="monospace"
android:text="@string/hello" />
<TextView
style="@style/CodeFont"
android:text="@string/hello" />
© JMF (Tous droits réservés) 11
,ichier de st*les

Dn #ichier de styles est un #ichier $M% de nom -uelcon-ue rangé dans
res/values9 Son noeud racine doit Atre resources9 E&emple

(ha-ue style est un élément $M% style9 %e nom du style est la valeur de
l*attri2ut name9 l contient une suite de sous éléments item précisant une
partie du style9 %e corps de la 2alise item est la valeur de cet item

%es styles peuvent Atre rangés par ar2orescence9 ,n le précise par l*attri2ut
(optionnel) parent
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CodeFont" parent="@android:style/TextAppearance.Medium">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">#00FF00</item>
<item name="android:typeface">monospace</item>
</style>
</resources>
© JMF (Tous droits réservés) 12
Hérita-e des st*les

8é#inir une nouvelle valeur pour un attri2ut de style écrase l*ancienne valeur
(si elle e&iste) pour cet attri2ut

,n peut hériter de styles prédé#inis par Android et, dans ce cas, on utilise
parent comme dans '

,n peut hériter de ses propres styles et, dans ce cas, on utilise la notation .
comme dans '
%e style dé#ini est CodeFont.Red9 l récupère les valeurs du style
CodeFont9 ,n l*utilise comme dans @style/CodeFont.Red

,n peut créer une ar2orescence de style comme CodeFont.Red.Big
<style name="GreenText" parent="@android:style/TextAppearance">
<item name="android:textColor">#00FF00</item>
</style>
<style name="CodeFont.Red">
<item name="android:textColor">#FF0000</item>
</style>
© JMF (Tous droits réservés) 13
Les th+mes

Dn style appli-ué + un Viewgroup ne se propage pas pour les composants
contenus dans le ViewGroup

Dn thème appli-ué + une activité est propagé + tous les composants de
l*activité

%es indications de thème sont écrits dans le AndroidManifest.xml +
l*aide l*attri2ut android:theme de la 2alise application '

,n peut utiliser les thèmes prédé#inis d*Android '

%es styles et thèmes proposés par Android sont accessi2les + partir de
http://developer.android.com/guide/topics/ui/themes.html#Platfo
rmStyles
<application android:theme="@style/CodeFont">
<activity android:theme="@android:style/Theme.Dialog">
© JMF (Tous droits réservés) 14
Composants IHM avancés

(ertains composants graphi-ues permettent d*a##icher 2eaucoup d*items
par des mécanismes de dé#ilement9 (e sont '

les Spinner, les Gallery, les GridView, les ListView

l y en a d*autres9 Eoir + Apis 8emos F Eie<s
© JMF (Tous droits réservés) 15
AdapterView et Adapter

%es composants graphi-ues -ui a##ichent un ensem2le d*items sont des
AdapterViews

(es composants sont très utiles si les données -u*ils a##ichent ne sont pas
connues + la création du programme mais seront chargées dynami-uement

Pour #ournir les items + ces composants graphi-ues, on utilise des Adapter

(omme AdapterView est en #ait AdapterView<T extends
android.widget.Adapter>, un AdapterView est touCours associé + un
Adapter

%*Adapter sert de lien avec les données + a##icher et l*AdapterView9 Gre#
c*est le design pattern adapter

%es AdapterView gèrent aussi les événements (i9e9 les interactions) sur le
composant graphi-ue avec le-uel ils sont associés9 (*est + la #ois un design
pattern vue et controleur
© JMF (Tous droits réservés) 16
AdapterView$ Adapter et
compa-nie . %1&2'

android.widget.AdapterView<T extends
android.widget.Adapter> est une classe a2straite généri-ue

android.widget.Adapter est une inter#ace9 Geaucoup de classes
implémentent cette inter#ace ' ArrayAdapter<T>, BaseAdapter

SpinnerAdapter et ListAdapter sont des inter#aces -ui héritent
de Adapter

Spinner, Gallery, GridView, ListView sont des sous classes
concrètes d*AdapterView

%*association entre un AdapterView et un Adapter est #aite +
l*aide de la méthode
public void setAdapter (T adapter)

Huestion ' ,I est indi-ué -ue le paramAtre T est un type
implémentant Adapter J

0éponse ' 8ans la dé#inition de la classe AdapterView
© JMF (Tous droits réservés) 17
AdapterView$ Adapter et
compa-nie . %2&2'

,n a donc '
© JMF (Tous droits réservés) 18
!utoriau# pour les
AdapterView

Geaucoup de documentation e&iste pour les AdapterView

8ans la documentation .o##icielle., on a des tutoriau& sur ces composants +
partir de la dé#inition de leur classe '

Spinner '
http://developer.android.com/guide/topics/ui/controls/
spinner.html

Gallery ' est, en #ait, dépréciée + partir de l*AP 4:9 l #aut utiliser des
HorizontalScrollView et des ViewPager

GridEie< '
http://developer.android.com/guide/topics/ui/layout/gr
idview.html

%istEie< '
http://developer.android.com/guide/topics/ui/layout/li
stview.html
© JMF (Tous droits réservés) 19
Spinner

(*est le composant graphi-ue Android similaire au (om2o 2o&
d*autres 2i2liothè-ues9 (*est un 2outon menu

Dn clic sur amène
© JMF (Tous droits réservés) 20
Spinner " construction de
lIHM %1&3'

%es étapes sont '

4K) récupérer le composant Spinner du #ichier d*!M

7K) construire la liste des items

?K) créer l*adapter associé + cette liste

LK) associer l*adapter au Spinner

A partir de
4K) est o2tenu par
<Spinner
android:id="@+id/spnMusketeers"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="2dp"
/>
Spinner spnMusketeers = (Spinner) findViewById(R.id.spnMusketeers);
© JMF (Tous droits réservés) 21
Spinner " construction de
lIHM %2&3'

7K) construire la liste des items est o2tenu par '

?K) créer l*adapter associé + cette liste est o2tenu par '

0emar-ue ' %e #ormat
android.R.layout.simple_spinner_item est un #ormat
donné par la 2i2liothè-ue d*Android9 (e n*est pas un #ichier d*!M de
l*application9 8*ailleurs il n*y a pas android.R pour les #ichiers $M%
d*une application mais simplement R.
List<String> lsMusketeers = new ArrayList<String>();
lsMusketeers.add("Athos");
lsMusketeers.add("Porthos");
lsMusketeers.add("Aramis");
ArrayAdapter<String> aspnMusketeers =
new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,lsMusketeers);
© JMF (Tous droits réservés) 22
Spinner " construction de
lIHM %3&3'

%e code précédent #ait apparaMtre '
(e n*est pas 2ien 2eau N ,n aCoute plut"t
pour avoir

0emar-ue ' android.R.layout.simple_spinner_dropdown_item
est aussi un #ormat donné par la 2i2liothè-ue Android

LK) associer l*adapter au Spinner est o2tenu par '
aspnMusketeers.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spnMusketeers.setAdapter(aspnMusketeers);
© JMF (Tous droits réservés) 23
Spinner " -estion des
événements

%e listener associé + un Spinner est un OnItemSelectedListener (et
pas un OnClickListener)

Otre un ItemSelectedListener nécessite de donner un corps + deu&
méthodes '
public void onItemSelected (AdapterView<?> parent, View
view, int position, long id)
avec
parent ' l*AdapterView sur le-uel l*interaction s*est produite
view ' le composant graphi-ue dans l*AdapterView -ui a été sélectionné
position ' l*indice de view dans l*AdapterView
id ' l*identi#icateur de l*item sélectionné
est la méthode invo-uée -uand un item du Spinner est sélectionné9 Elle
est invo-uée seulement si un nouveau choi& a été #ait

0emar-ue ' parent.getItemAtPosition(position) retourne la
donnée associée + l*item sélectionné
© JMF (Tous droits réservés) 24
Spinner " le code complet

source ' P?Q page 4R6
Spinner spnMusketeers = (Spinner) findViewById(R.id.spnMusketeers);
// Positionne les items du Spinner
List<String> lsMusketeers = new ArrayList<String>();
lsMusketeers.add("Athos");
lsMusketeers.add("Porthos");
lsMusketeers.add("Aramis");
ArrayAdapter<String> aspnMusketeers =
new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,lsMusketeers);
aspnMusketeers.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spnMusketeers.setAdapter(aspnMusketeers);
// gestion des événements
spnMusketeers.setOnItemSelectedListener(
new OnItemSelectedListener() {
public void onNothingSelected(AdapterView<?> arg0) { }
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
// code appelé lorsqu'un item est sélectionné
String obj = (String)parent.getItemAtPosition(position);
Toast leToast = Toast.makeText(AdapterProjetActivity.this,
"item sélectionné : " + obj, Toast.LENGTH_LONG);
leToast.show();
}
});
© JMF (Tous droits réservés) 25
Gallery

Sait apparaMtre ses éléments comme des ta2leau& dans une gallerie
(d*art)

%e dé#ilement des items est hori3ontal

%*élément principal est centré et ses voisins
.en arrière plan.

Est un Spinner particulier '

Eoir démo proCet !elloGallery

source ' P?Q page 4RT
© JMF (Tous droits réservés) 26
Les items dune Gallery

(omme une Gallery est un AdapterView, les items d*une
Gallery sont #ournis par un Adapter9 (omme les éléments d*une
Gallery ne sont pas des String, on utilise pour cela la classe
a2straite android.widget.BaseAdapter

,n indi-ue le composant graphi-ue #a2ri-ué pour le position
ième élement de l*adapter par la méthode
public View getView (int position, View
convertView, ViewGroup parent) oI position est le
numéro (commenUant + 0) de l*élément dans l*adapter

Pour une Gallery, la présentation .image sélectionné centrée, les
voisines en arrière plan. est donné par une propriété Android
Theme_galleryItemBackground9 l #aut positionner cette valeur
pour cha-ue image créée pour cha-ue item

source ' P?Q
© JMF (Tous droits réservés) 27
Gallery " le code %1&/'

l #aut déC+ avoir un ensem2le d*images N (+ déposer dans
res/drawable)

%e #ichier !M (res/layout/main.xml) contient '

%*activité -ui a##iche la Gallery a essentiellement pour code '
<?xml version="1.0" encoding="utf-8"?>
<Gallery xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gallery"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
public class HelloGallery extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Gallery gallery = (Gallery) findViewById(R.id.gallery);
gallery.setAdapter(new MonImageAdapter(this));
// ... pour un listener
}
}
© JMF (Tous droits réservés) 28
Gallery " le code %2&/'

%*adapter associé + la Gallery est donc un o2Cet de la classe
MonImageAdapter

Pour placer cha-ue item de la Gallery, il #aut préciser un layout9
,n utilise le placement prédé#ini galleryItemBackground9 ,n a
alors le #ichier res/values/attrs.xml -ui décrit l*a##ichage des
items

%a classe MonImageAdapter commence comme '
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="HelloGallery">
<attr name="android:galleryItemBackground" />
</declare-styleable>
</resources>
public class ImageAdapter extends BaseAdapter {
int mGalleryItemBackground;
private Context mContext;
private Integer[] mImageIds = {
R.drawable.sample_1, ...
};
© JMF (Tous droits réservés) 29
Gallery " le code %3&/'

%a classe MonImageAdapter continue par son constructeur '

%e conte&te c est nécessaire pour d*autres méthodes de la classe

Dn android.content.res.TypedArray un ensem2le de valeur
de type de style9 ,n récupère celle associée au style .gallery item
pour l*application. et on la positionne dans la donnée mem2re
mGalleryItemBackground

l est conseillé de touCours appeler recycle() sur un TypedArray
pour une éventuelle réutilisation (c*est pas le cas ici mais 2on /1))
public MonImageAdapter(Context c) {
mContext = c;
TypedArray attr = mContext.obtainStyledAttributes(R.styleable.HelloGallery);
mGalleryItemBackground = attr.getResourceId(
R.styleable.HelloGallery_android_galleryItemBackground, 0);
attr.recycle();
}
© JMF (Tous droits réservés) 30
Gallery " le code %0&/'

%ors-u*on construit son propre Adapter comme ici notre
MonImageAdapter pour un AdapterView, il #aut indi-uer le
composant graphi-ue -ui sera a##iché comme position ième item
de cet AdapterView9 (eci est indi-ué + l*aide de la méthode
View getView(int position, ...) -ui retourne un tel
composant graphi-ue

(ette méthode getView() est appelée automati-uement par
l*envirionnment d*e&écution et retourne la View pour l*item d*indice
position
© JMF (Tous droits réservés) 31
Gallery " le code %1&/'

Eoici la méthode getView() pour la classe MonImageAdapter '

Ele construit une ImageView + partir des images dans
res/drawable, indi-ue la taille de cette image 4V;&4;; pi&els,
précise -ue l*image originelle doit Atre tout entière contenue dans ce
rectangle 4V;&4;; (FIT_XY), positionne un #ond chatoyant pour
une image, 2re# un cadre (par mGalleryItemBackground)9 Elle
retourne en#in cette ImageView
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(mContext);
imageView.setImageResource(mImageIds[position]);
imageView.setLayoutParams(new Gallery.LayoutParams(150, 100));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setBackgroundResource(mGalleryItemBackground);
return imageView;
}
© JMF (Tous droits réservés) 32
Gallery " le code %/&/'

l #aut donner un corps au& méthodes getCount(), getItem(),
getItemId() -ui sont a2straites dans la classe de 2ase
BaseAdapter, d*oI leur code '

Huestion )ava ' pour-uoi return un int convient pour retourner un
Object dans la méthode getItem() J
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}

0éponse ' c*est l*auto2o&ing de )ava 49V, un o2Cet .enveloppe.
Integer est #a2ri-ué + partir de l*int et est retourné
© JMF (Tous droits réservés) 33
Interaction sur une
Gallery

,n gère les interactions utilisateurs sur une Gallery + l*aide d*un
OnItemClickListener9 %e code d*interaction peut Atre '

%a méthode
public void onItemClick (AdapterView<?> parent,
View view, int position, long id) + implémenter a pour
arguments '

parent ' l*AdapterView -ui a reUu le clic de l*utilisateur

view ' la View -ui a reUu le clic

position ' l*indice de cette View dans l*adapter

id ' l*identi#iant de la View -ui a reUu le clic
gallery.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
Toast.makeText(HelloGallery.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
© JMF (Tous droits réservés) 34
GridView

Sait apparaMtre ses éléments dans une grille (ta2leur) ligne1colonne

%e dé#ilement des items est hori3ontal ou vertical

%*ar2orescence des classes est '

8émo proCet !elloGridEie<
© JMF (Tous droits réservés) 35
GridView " le code %1&2'

l est similaire + celui de la Gallery

%e #ichier !M (res/layout/main.xml) est '

%a classe MonImageAdapter commence par '
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="90dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
public class MonImageAdapter extends BaseAdapter
{
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
© JMF (Tous droits réservés) 36
GridView " le code %2&2'

%a méthode getView() est '
// Créé une ImageView pour chaque item référencé dans l'Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
// si ConvertView n'a pas été récupéré, construire une ImageView
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
© JMF (Tous droits réservés) 37
Le composant ListView

.A (%ist)vie< (that) sho<s items in a vertically scrolling
list9 The items come #rom the ListAdapter associated
<ith this vie<9. (W)

Par#ois les items proviennent d*un accès distant

!éritage de ListView '

Dne ListView est donc un AdapterView -ui est
.a vie< <hose children are determined 2y an Adapter9. (WW)

sources ' (W)
http://developer.android.com/reference/android/widget/ListView.html
(WW)
http://developer.android.com/reference/android/widget/AdapterView.ht
ml
© JMF (Tous droits réservés) 39
Le composant ListView

l permet d*a##icher une (grande) liste d*items, accessi2le par dé#ilement
mais aussi par #iltre ' l*utilisateur tape les premières lettres, le ListView
n*a##iche plus -ue les items -ui commencent par ces lettres

Pour dé#inir un ListView, on commence par indi-uer comment sera
a##iché cha-ue item du ListView9 Par e&emple sous #orme de
TextView9 ,n construit donc le #ichier res/layout/list_item.xml '

Dne démo ' proCet !ello%istEie<
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10dp"
android:textSize="16sp" >
</TextView>
© JMF (Tous droits réservés) 40
Lactivité ListActivity

Dne ListView peut occuper tout l*écran9 8ans ce cas, elle peut Atre
construite + partir d*une android.app.ListActivity (-ui hérite de
android.app.Activity)

%ors-u*on construit une classe -ui hérite de ListActivity, on peut
alors utiliser plusieurs méthodes de la classe ListActivity '

public ListView getListView() -ui retourne le composant
graphi-ue ListView associé + cette activité

public void setListAdapter(ListAdapter adapter)
positionne le ListAdapter associé + la ListView de cette activité
ListActivity

Et on spécialise la méthode onCreate() (comme d*ha2) et on a une
Activity -ui présente une ListView
© JMF (Tous droits réservés) 41
ListView " 1er e#emple 2
laide de ListActivity'
public class HelloListViewActivity extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, COUNTRIES));
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// le code lancé lors de la sélection d'un item
}
});
}
static final String[] COUNTRIES = new String[] { ... }
}
© JMF (Tous droits réservés) 42
ArrayAdapter<T> pour
ListView

,n construit le ListAdapter + partir d*un
ArrayAdapter<String>9 En #ait on a l*ar2orescence
(d*inter#aces, de classe a2straite et de classe
généri-ue N) suivante '

,n a utilisé le constructeur '
public ArrayAdapter (Context context,
int textViewResourceId,
T[] objects)
car '
Activity dérive de Context '
textViewResourceId repère l*!M -ui modélise un
item
objects est le ta2leau de données + a##icher

%a ListView construite + partir de l*activité et récupérée
par getListView(), est sensi2le + la sélection par
pré#i&e grXce + l*appel
setTextFilterEnabled(true);
© JMF (Tous droits réservés) 43
2i+me e#emple " utiliser une
ListView dans une Activity

Dne ListView peut Atre construite + partir d*une Activity (et pas
d*une ListActivity)

8émo ' Eeli2ProCet
© JMF (Tous droits réservés) 44
3tiliser une ListView dans
une Activity

%a ListView est indi-uée dans un #ichier $M% d*!M

8ans le code )ava, on récupère cette ListView (par la méthode miracle
findViewById()) et on l*alimente d*items par '
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView android:layout_height="wrap_content"
android:layout_width="match_parent" android:id="@+id/listMenu">
</ListView>
</LinearLayout>
ListView laListe = (ListView) findViewById(R.id.listMenu);
Resources res = getResources();
String [] lesItems = new String[] {
res.getString(R.string.seeAllStations),
res.getString(R.string.aboutUs)
};
laListe.setAdapter(new ArrayAdapter<String>(this, R.layout.list_item, lesItems));

seeAllStations et aboutUs, 999 ont dé#inies dans
res/values/strings.xml
© JMF (Tous droits réservés) 45
ListView " la -estion des
événements

%a gestion des événements est assuré par l*auditeur
public void setOnItemClickListener
(AdapterView.OnItemClickListener listener)

AdapterView.OnItemClickListener est une inter#ace -ui demande
d*implémenter la méthode
public void onItemClick(AdapterView<?> parent, View view, int
position, long id)
-ui est lancée lors-ue l*utilisateur sélectionne un item de la ListView
parent est l*AdapterView -ui a été utilisé lors de l*événement
view est la View (c*est + dire l*item a l*intérieur de la ListView) -ui a été
utilisé
position est le numéro de l*item dans cette ListView9 %a valeur 0 est celle
du premier item
id est l*identi#icateur de l*item sélectionné
© JMF (Tous droits réservés) 46
3ne 4uestion 5ava

Pour-uoi la méthode
public void setOnItemClickListener
(AdapterView.OnItemClickListener listener)
-ui demande comme argument un AdapterView.OnItemClickListener peut
Atre utilisé par le code '
lv.setOnItemClickListener(new OnItemClickListener() { ... });
J

0éponse ' (ar Eclipse aCoute, après S!ST Y (T0% Y ,, le 2on import
import android.widget.AdapterView.OnItemClickListener;

Merci Sa2rice N
© JMF (Tous droits réservés) 47
6#ercice

(onstruire une activité présentant un ListView (4ère étape)

Gérer les a##ichages de l*écran suivant le choi& de l*utilisateur des
di##érents items de cette ListView (7ième étape)
© JMF (Tous droits réservés) 48
Afficher des ob7ets dans une
ListView

,n a une collection d*o2Cets, on voudrait les a##icher .Coliment. dans une
ListView

Par e&emple une liste d*DE constituant un dipl"me

Dne démo ' ProCet (erti#(ompet, onglet
.Dnités d*enseignement.

l s*agit de #aire a##icher une ArrayList<UE>
avec
constituant un dipl"me
public class UE {
private String nom, lieu, periode;
...
}
public class DiplomeCNAM {
private ArrayList<UE> lesUE;
public DiplomeCNAM() {
this.lesUE = new ArrayList<UE>();
...
}
public ArrayList<UE> getLesUE() {return lesUE; }
}
© JMF (Tous droits réservés) 49
Adapteur dob7ets pour une
ListView

,n construit un Adapter pour la ListView en dérivant de
BaseAdapter

l #aut donc donner un corps au& méthodes a2straites des classes
ancAtres '
public class LeBelAdapter extends BaseAdapter {
private DiplomeCNAM diplome;
...
public int getCount() {
return diplome.getLesUE().size();
}
public Object getItem(int position) {
return diplome.getLesUE().get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
// Détaillé plus loin
}
}
© JMF (Tous droits réservés) 50
LIHM de cha4ue item %1&3'

(omme d*ha2itude, l*!M de cha-ue item est décrit par le #ichier
res\layout\uecnam.xml '

8*a2ord un TextView de taille 4:sp
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="TextView" />

© JMF (Tous droits réservés) 51
LIHM de cha4ue item %2&3'

Puis un TableRow -ui #onctionne comme un LinearLayout hori3ontal
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/imageId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/orange01" >
>
</ImageView>
<TextView
android:id="@+id/lieuId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="12sp" >
</TextView>
</TableRow>
</LinearLayout>
© JMF (Tous droits réservés) 52
LIHM de cha4ue item %3&3'

%e TableRow contient une ImageView et un TextView

%*ImageView contient l*image orange01 comme valeur par dé#aut

%e TextView contient Te&tEie< comme te&te par dé#aut

%*apparence du te&te est l*apparence standard de l*AP Android,
textAppearanceMedium -ui est dé#ini par le #ichier platforms\android-
X\data\res\values\themes.xml du sdB -ui contient '
-ui redirige en #ait sur \platforms\android-
X\data\res\values\styles.xml -ui contient '

source ' http://stackoverflow.com/questions/11590538/dpi-value-of-
default-large-medium-and-small-text-views-android
<item name="textAppearanceLarge">@android:style/TextAppearance.Large</item>
<item name="textAppearanceMedium">@android:style/TextAppearance.Medium</item>
<item name="textAppearanceSmall">@android:style/TextAppearance.Small</item>
<style name="TextAppearance.Medium">
<item name="android:textSize">18sp</item>
<item name="android:textStyle">normal</item>
<item name="android:textColor">?textColorPrimary</item>
</style>
© JMF (Tous droits réservés) 53
La méthode getView() de
ladapteur %1&2'

(*est cette méthode -ui construit la View de cha-ue item de la
ListView

,n peut l*écrire ainsi '
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = null;
inflater = (LayoutInflater)
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.uecnam, parent, false);
TextView nomView = (TextView)itemView.findViewById(R.id.textView1);
ImageView imageView = (ImageView)itemView.findViewById(R.id.imageId);
TextView lieuView = (TextView)itemView.findViewById(R.id.lieuId);
nomView.setText(diplome.getLesUE().get(position).getNom());
lieuView.setText(diplome.getLesUE().get(position).getLieu());
String periode = diplome.getLesUE().get(position).getPeriode();
if (periode.equals("1")) {
imageView.setImageResource(R.drawable.orange01);
} else {
imageView.setImageResource(R.drawable.green02);
}
return itemView;
}
© JMF (Tous droits réservés) 54
La méthode getView() de
ladapteur %2&2'

(ette méthode récupère l*analyseur $M% (un LayoutInflater) de
#ichier d*!M, puis chacun des composants graphi-ues et positionne avec
des valeurs précises #onction du numéro de l*item dans la %istEie<
associée + cet adapteur

,n a donc un e&emple de construction graphi-ue en partie stati-ue (+
l*aide d*un #ichier $M%) pour les valeurs générales, et en partie
dynami-ue (+ l*aide de la programmation) pour les parties varia2les
© JMF (Tous droits réservés) 55
3n cache pour la
construction des items

%e pro2lème avec l*écriture de getView() précédente est -ue cette
méthode est lancée pour cha-ue item

Et donc l*analyse $M% du #ichier d*!M est #aite pour cha-ue item 999

alors -ue cela donne touCours le mAme résultat N

%es parties de programmation communes doivent Atre #aites -u*une
seule #ois

,n utilise un cache '
class CacheView {
private TextView nomView;
private ImageView imageView;
private TextView lieuView;
// accesseurs set/get pour ces champs
...
}
© JMF (Tous droits réservés) 56
Le fonctionnement dune
List8ie9

Dne %istEie< garde trace des Eie< de cha-ue item déC+ construit9 (*est une
réserve de .ScrapEie<. '
.ScrapEie<s are old vie<s that could potentially 2e used 2y the adapter to avoid
allocating vie<s
unnecessarily. (https://github.com/android/platform_frameworks_b
ase/blob/43ee0ab8777632cf171b598153fc2c427586d332/core/java/
android/widget/AbsListView.java#L5764)

source ' http://lucasr.org/2012/04/05/performance-tips-for-
androids-listview/
© JMF (Tous droits réservés) 57
Association de données 2
une View

,n peut donc réutiliser si possi2le les ScrapEie<s

%ors-ue getView() est lancé, l*argument convertView repère
éventuellement une ScrapEie< -ui correspond + l*item + a##icher9 Si c*est
le cas, inutile de re#ère l*analyse $M%9 Si ce n*est pas le cas, on construit
la vue de cet item et on lui associe des données particulières

,n associe des données supplémentaires + une View + l*aide de sa
méthode public void setTag (Object tag) (de la classe View)

,n récupère des données supplémentaires + une View + l*aide de sa
méthode public Object getTag() (de la classe View)

l su##it alors, la #ois suivante, si on a récupérer une ScrapEie< pour
l*tem, de rechercher ces données
© JMF (Tous droits réservés) 58
Réécriture de getView()

8*ou le code .optimisé. de getView() (et merci Cean1michel)
public View getView(int position, View convertView, ViewGroup parent) {
View itemView = convertView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.uecnam, parent, false);
CacheView cache = new CacheView();
cache.setNomView((TextView)itemView.findViewById(R.id.textView1));
cache.setImageView((ImageView)itemView.findViewById(R.id.imageId));
cache.setLieuView((TextView)itemView.findViewById(R.id.lieuId));
itemView.setTag(cache);
}
CacheView cache = (CacheView)itemView.getTag();
cache.getNomView().setText(diplome.getLesUE().get(position).getNom());
cache.getLieuView().setText(diplome.getLesUE().get(position).getLieu());
String periode = diplome.getLesUE().get(position).getPeriode();
if (periode.equals("1")) {
cache.getImageView().setImageResource(R.drawable.orange01);
} else {
cache.getImageView().setImageResource(R.drawable.green02);
}
return itemView;
}
© JMF (Tous droits réservés) 59
La :3I !hread:

8ans une application Android, il e&iste une et une seule thread -ui
gère l*inter#ace graphi-ue ' la D Thread (Dser nter#ace Thread)

.There is one main application thread (.D thread.) per process,
supporting all activities, services, and 2roadcast receivers in that
process., MarB Murphy auteur de .The Gusy (oder*s Guide to
Android 8evelopment.

Tout ce -ui concerne l*a##ichage est (et doit Atre) géré par cette
Thread9 Si une autre Thread s*occupe de #aire de l*a##ichage
graphi-ue, il y a erreur + l*e&écution

%ors-u*un travail demandant du temps est lancé, il #aut le #aire dans
une Thread autre -ue la D Thread9 Au 2esoin en créé une N

Au lieu de créer de telles threads et de les gérer, Android propose
une classe -ui gère correctement cela9 (*est la classe (généri-ue N)
android.os.AsyncTask<Params, Progress, Result>
© JMF (Tous droits réservés) 60
La classe
android.os.AsyncTask<Params, Progress, Result>

Elle est #aite pour gérer correctement la gestion entre une thread
(de traitement long) et la D Thread

Elle permet de lancer un traitement en arrière plan et de mettre +
Cour (éventuellement de temps en temps) l*inter#ace graphi-ue de
l*application

%es paramAtres généri-ues sont utilisés pour '

Params ' le type des paramAtres nécessaires + la tXche en
arrière plan

Progress ' le type de paramAtre reUus par la méthode de mise
+ Cour

Result ' le type de résultat retourné par la tXche en arrière
plan
© JMF (Tous droits réservés) 61
Les méthodes de
AsyncTask<Params, Progress, Result>

(ette classe contient L méthodes dont trois d*entre elles sont e&écutées
dans la D Thread9 (e sont ' onPreExecute(),
onProgressUpdate(Progress...), onPostExecute(Result) -ui
sont e&écutées dans la D Thread et doInBackground(Params...) lancé
dans une autre thread

onPreExecute() est e&écuté avant le lancement de la tXche d*arrière plan

doInBackground(Params...) est lancé après onPreExecute() dans
une thread autre -ue la D Thread ' c*est le traitement en arrière plan9 %es
paramAtres de type Params sont passés + cette méthode9 (ette méthode
retourne un resultat de type Result (-ui sera e&ploité par
onPostExecute(Result))9 (ette méthode peut lancer
publishProgress(Progress...) -ui permet de lancer
onProgressUpdate(Progress...) dans la D Thread et mettre ainsi +
Cour l*!M de l*application, tout en continuant la tXche en arrière plan

onPostExecute(Result) est lancé après la #in de la tXche en arrière
plan9 (ette méthode reUoit le paramAtre de type Result -u*a renvoyé
doInBackground(Params...)
© JMF (Tous droits réservés) 62
3tilisation de
AsyncTask<Params, Progress, Result>

Pour utiliser cette classe, il #aut la sous classer, construire une instance de
cette sous1classe et lancer la méthode de type execute(Params ...) sur
cette instance

l #aut au moins redé#inir la méthode doInBackground(Params...) (2on
sens N)

%a sous classe créée est souvent une sous1classe interne + une méthode

%a création de l*instance de cette sous classe doit Atre #aite dans la D
Thread et execute(Params ...) doit Atre lancée sur cette instance une
seule #ois dans la D Thread

%es méthodes onPreExecute(), doInBackground(Params...),
onProgressUpdate(Progress...), onPostExecute(Result) ne
doivent pas Atre lancées e&plicitement ' c*est la méthode execute() -ui
déclenche le tout
© JMF (Tous droits réservés) 63
6#emple de code de
AsyncTask<Params, Progress, Result>
class ChargementDesStationsTache extends AsyncTask<String, String, String> {
protected void onPreExecute() {
progress = ProgressDialog.show(ListingDesStationsActivity.this,
getResources().getString(R.string.app_name),
getResources().getString(R.string.chargement_message),
true);
}
protected String doInBackground(String ... urls) {
// charger les stations
try {
sp = new StationsParser(getBaseContext());
} catch (Exception e) { e.printStackTrace(); }
leStationsAdapter = new StationsAdapter(getBaseContext(),
ListingDesStationsActivity.this, sp.getArrList()) ;
return null;
}
protected void onProgressUpdate(String... aAfficher) { }
protected void onPostExecute(String result) {
// arréter le progressDialog
progress.dismiss();
// mettre à jour la ListView des stations
listing.setAdapter(leStationsAdapter);
}
}
new ChargementDesStationsTache().execute();
© JMF (Tous droits réservés) 64
Confi-uration de
lAndroidManifest.xml

(omme l*application demande + utilliser l*internet, il #aut l*indi-uer dans le
#ichier AndroidManifest.xml par '
<uses-permission android:name="android.permission.INTERNET" />
#ils de l*élément manifest

(omme l*application demande + utiliser une nouvelle Activity, il #aut
l*indi-uer dans le #ichier AndroidManifest.xml par '
<activity android:name=".ListingDesStationsActivity" />
#ils de l*élément application

Par e&emple '
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=... >
...
<uses-permission android:name="android.permission.INTERNET" />

<application ...
...
<activity android:name=".ListingDesStationsActivity" />
</application>
</manifest>
© JMF (Tous droits réservés) 65
6#ercice

Ecrire une activité contenant une ListView alimentée par des
données se trouvant + une D0%
© JMF (Tous droits réservés) 66
;iblio-raphie pour ce
chapitre

P4Q ' Pour ce chapitre
http://developer.android.com/guide/topics/ui/index.html

P7Q ' The Gusy (oder*s Guide to Android 8evelopment, MarB %9
Murphy / editions (ommonsZare

P?Q ' Android Application 8evelopment, 0icB 0ogers, )ohn
%om2ardo, [igurd MednieBs and GlaBe MeiBe / editions ,*0eilly, 7;;R

Pour l*optimisation de %istEie< ' polycopié de cours
%istEie<\ntroduction de )ean1Michel 8ouin et
http://lucasr.org/2012/04/05/performance-tips-for-
androids-listview/
© JMF (Tous droits réservés) 67
,in