I. Les IHMs des Activités - éléments complexes▲
I-A. Les onglets▲
Pour la mise en place d'onglets, il faut s'appuyer sur les widgets suivants :
- TabHost est le conteneur général ;
- TabWidget implémente la ligne des boutons d'onglets (qui contiennent labels, icônes ou une vue) ;
- FrameLayout est le conteneur des contenus des onglets : chaque onglet est un fils de FrameLayout.
Il existe un TabActivity, comme ListActivity, qui encapsule un motif d'interface graphique classique dans une sous-classe d'activité. Ce n'est pas nécessaire, une activité classique peut très bien utiliser également des onglets.
Quelques règles syntaxiques :
- L'identifiant du TabWidget doit être @android :id/tabs ;
- Dans le cas d'une TabActivity l'identifiant du TabHost est @android :id/tabhost.
Exemple de la définition statique d'onglets:
<?
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
"
>
<
TabHost
android
:
id
=
"
@+id/tabhost
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
TabWidget
android
:
id
=
"
@android:id/tabs
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
/
>
<
FrameLayout
android
:
id
=
"
@android:id/tabcontent
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
paddingTop
=
"
62px
"
>
<
DigitalClock
android
:
id
=
"
@+id/digital
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
layout_centerHorizontal
=
"
true
"
/
>
<
AnalogClock
android
:
id
=
"
@+id/analog
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
android
:
layout_centerHorizontal
=
"
true
"
android
:
layout_alignParentTop
=
"
true
"
/
>
<
/
FrameLayout
>
<
/
TabHost
>
<
/
LinearLayout
>
On remarque que TabHost contient deux objets distincts, le TabWidget qui est la ligne des boutons d'onglets et le FrameLayout qui lui contient les onglets. Ainsi, c'est le FrameLayout qui contient les widgets visualisés dans l'onglet.
public
class
StaticTabPane extends
Activity {
/**
Called
when
the
activity
is
first
created
.
*/
@
Override
public
void
onCreate
(
Bundle savedInstanceState) {
//
Instanciation
of
the
View
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.main);
//
Instanciation
of
the
Tab
Host
the
one
that
contains
the
tabPanels
TabHost tabs =
(
TabHost) findViewById
(
R.id.tabhost);
tabs.setup
(
);
//
Instanciation
of
the
first
tab
component
TabHost.TabSpec spec =
tabs.newTabSpec
(
"
digital
"
);
spec.setContent
(
R.id.digital);
//
Definition
of
the
label
to
display
for
the
tabPanel
spec.setIndicator
(
"
Digital
Clock
"
);
//
Adding
the
first
tabPanel
to
the
TabHost
tabs.addTab
(
spec);
//
Instanciation
of
the
second
tab
component
spec =
tabs.newTabSpec
(
"
analogic
"
);
spec.setContent
(
R.id.analog);
//
Definition
of
the
label
to
display
for
the
tabPanel
spec.setIndicator
(
"
Analogic
Clock
"
);
//
Adding
the
second
tabPanel
to
the
TabHost
tabs.addTab
(
spec);
}
}
Exemple pour la manipulation dynamique de la création d'onglets. Le fichier de déclaration GUI ci-dessus change à peine, l'AnalogClock étant remplacée par un Button :
<
LinearLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
orientation
=
"
vertical
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
TabHost
android
:
id
=
"
@+id/tabhost
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
TabWidget
android
:
id
=
"
@android:id/tabs
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
/
>
<
FrameLayout
android
:
id
=
"
@android:id/tabcontent
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
paddingTop
=
"
62px
"
>
<
DigitalClock
android
:
id
=
"
@+id/digital
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
layout_centerHorizontal
=
"
true
"
/
>
<
Button
android
:
id
=
"
@+id/button
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
text
=
"
Bouton
semi-aleatoire
"
/
>
<
/
FrameLayout
>
<
/
TabHost
>
<
/
LinearLayout
>
Seul le code Java change fortement :
public
class
DynamicTabPane extends
Activity {
/**
*
The
tabHost
*/
TabHost tabHost;
/**
*
The
On
click
Listener
*/
private
OnClickListener ocl =
new
View.OnClickListener
(
) {
public
void
onClick
(
View view) {
addTabSpec
(
);
}
}
;
/**
*
The
Button
that
adds
a
new
TabSpec
*/
private
Button btn;
@
Override
public
void
onCreate
(
Bundle icicle) {
//
Instanciate
the
activity
super
.onCreate
(
icicle);
setContentView
(
R.layout.main);
//
Instanciate
the
TabHost
tabHost =
(
TabHost) findViewById
(
R.id.tabhost);
tabHost.setup
(
);
//
Instanciate
the
first
tabPanel
TabHost.TabSpec tabSpec =
tabHost.newTabSpec
(
"
digital
"
);
tabSpec.setContent
(
R.id.digital);
tabSpec.setIndicator
(
"
Clock
"
);
//
Adding
the
first
tabPanel
tabHost.addTab
(
tabSpec);
//
Instanciate
the
second
tabPanel
tabSpec =
tabHost.newTabSpec
(
"
button
"
);
tabSpec.setContent
(
R.id.button);
tabSpec.setIndicator
(
"
Button
"
);
//
Adding
the
second
tabPanel
tabHost.addTab
(
tabSpec);
//
Adding
functionalities
to
the
button:
When
a
clic
is
done,
a
new
TabPanel
is
created
btn =
(
Button) findViewById
(
R.id.button);
if
(
btn =
=
null
) {
Toast.makeText
(
this
, "
nullPointeur
exception
"
, Toast.LENGTH_LONG).show
(
);
}
else
{
Toast.makeText
(
this
, "
not
nullPointeur
exception
"
, Toast.LENGTH_LONG).show
(
);
btn.setOnClickListener
(
ocl);
}
}
/**
*
@param
tabHost
*/
private
void
addTabSpec
(
) {
Toast.makeText
(
this
, "
A
new
tab
is
created
"
, Toast.LENGTH_LONG).show
(
);
//
Retrieve
the
TabSpec
of
the
TabHost
and
creating
a
new
entry
TabHost.TabSpec spec =
tabHost.newTabSpec
(
"
analogic
"
);
//
Creating
a
new
content
to
the
tabPanel
using
TabContent
factory
spec.setContent
(
new
TabHost.TabContentFactory
(
) {
public
View createTabContent
(
String tag) {
//
This
method
has
to
return
a
view,
the
tag
is
the
one
define
by
TabSpec
return
(
new
AnalogClock
(
getApplicationContext
(
)));
}
}
);
//
or
using
an
already
defined
element:
//
spec.setContent(R.id.digital);
//
Define
the
Tab
label
spec.setIndicator
(
"
Analogic
"
);
//
Adding
the
new
tabPanel
to
the
TabHost
tabHost.addTab
(
spec);
}
}
I-A-1. Une autre activité dans un onglet▲
I-B. Les vues basculantes : ViewFlipper▲
On peut souhaiter pouvoir avoir des onglets sans barre d'onglets, c'est-à-dire basculer d'une vue à une autre au sein de l'activité.
Cela est possible avec l'objet ViewFlipper qui hérite de FrameLayout. Le basculement entre les vues est alors à mettre en place (contrairement aux onglets où le processus est pris en charge par les TabWidget).
I-B-1. Vue basculante statique▲
L'objet principal est ViewFlipper, qui se décrit dans le layout.xml, et sa méthode showNext.
<
LinearLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
orientation
=
"
vertical
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
Button
android
:
id
=
"
@+id/flip
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
android
:
text
=
"
Flip
!
"
/
>
<
ViewFlipper
android
:
id
=
"
@+id/flipper
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
TextView
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
android
:
text
=
"
first
"
/
>
<
TextView
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
android
:
text
=
"
second
"
/
>
<
/
ViewFlipper
>
<
/
LinearLayout
>
Et le code associé :
public
class
FlipTuto extends
Activity {
/**
*
The
flipperView
View
*/
ViewFlipper flipperView;
@
Override
public
void
onCreate
(
Bundle icicle) {
super
.onCreate
(
icicle);
setContentView
(
R.layout.main);
//
Retrieve
the
flipperView
flipperView =
(
ViewFlipper) findViewById
(
R.id.flipper);
//
Instanciate
the
button
Button btn =
(
Button) findViewById
(
R.id.flip);
//
When
the
button
is
click,
just
flip
to
the
next
element
btn.setOnClickListener
(
new
View.OnClickListener
(
) {
public
void
onClick
(
View view) {
flipperView.showNext
(
);
}
}
);
}
}
I-B-2. Vue basculante dynamique▲
Exemple d'ajout de vues à la volée :
Le descripteur d'IHM ne décrit pas le contenu du ViewFlipper :
<
LinearLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
orientation
=
"
vertical
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
ViewFlipper
android
:
id
=
"
@+id/details
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
/
ViewFlipper
>
<
/
LinearLayout
>
Le code Java:
public
class
FlipDynamicTuto extends
Activity {
/**
*
The
dummy
data
list
*/
static
String[] items =
{
"
item1
"
, "
item2
"
, "
item3
"
, "
item4
"
, "
item5
"
, "
item6
"
}
;
/**
*
The
viewFlipper
*/
final
ViewFlipper viewFlipper;
@
Override
public
void
onCreate
(
Bundle icicle) {
super
.onCreate
(
icicle);
setContentView
(
R.layout.main);
//
Retrieve
the
viewFlipper
viewFlipper =
(
ViewFlipper) findViewById
(
R.id.details);
//
Define
animation
object
for
the
flip
viewFlipper.setInAnimation
(
AnimationUtils.loadAnimation
(
this
, R.anim.push_left_in));
viewFlipper.setOutAnimation
(
AnimationUtils.loadAnimation
(
this
, R.anim.push_left_out));
//
Add
view
for
(
String item : items) {
Button btn =
new
Button
(
this
);
btn.setText
(
item);
//
When
the
button
is
click,
just
flip
to
the
next
element
btn.setOnClickListener
(
new
View.OnClickListener
(
) {
public
void
onClick
(
View view) {
viewFlipper.showNext
(
);
}
}
);
//
Add
a
new
View
to
the
viewFlipper.
viewFlipper.addView
(
btn, new
ViewGroup.LayoutParams
(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
}
//
Or
make
an
automatic
flipping
(in
ms)
viewFlipper.setFlipInterval
(
2000
);
//
And
launch
it
viewFlipper.startFlipping
(
);
}
}
Les descripteurs d'animations :
res\anim\push_left_in.xml:
<
set
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
>
<
translate
android
:
fromXDelta
=
"
100%p
"
android
:
toXDelta
=
"
0
"
android
:
duration
=
"
300
"
/
>
<
alpha
android
:
fromAlpha
=
"
0.0
"
android
:
toAlpha
=
"
1.0
"
android
:
duration
=
"
300
"
/
>
<
/
set
>
res\anim\push_left_out.xml:
<
set
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
>
<
translate
android
:
fromXDelta
=
"
0
"
android
:
toXDelta
=
"
-100%p
"
android
:
duration
=
"
300
"
/
>
<
alpha
android
:
fromAlpha
=
"
1.0
"
android
:
toAlpha
=
"
0.0
"
android
:
duration
=
"
300
"
/
>
<
/
set
>
I-C. Les tiroirs : SlidingDrawer▲
Les tiroirs sont des widgets qui s'affichent et se cachent au-dessus de la vue courante. Pour cette raison, il ne peut être le fils que des layouts de type RelativeLayout ou FrameLayout.
Un tiroir (SlidingDrawer) est défini par une poignée (le plus souvent ImageView) et un contenu qu'il pointe au travers des balises android:handle et android:content. L'ouverture et la fermeture par toucher de la poignée sont automatiquement gérées par la poignée.
Les méthodes utiles à l'emploi de ce widget sont :
- open(), close(), toggle() pour ouvrir, fermer et switcher instantanément ;
- animateOpen, animateClose, animateToggle pour ouvrir, fermer et switcher en utilisant une animation ;
- lock, unlock désactive/active l'écoute des clics utilisateurs ;
- ajouter des écouteurs pour l'ouverture du tiroir, sa fermeture, son mouvement.
Exemple :
Descripteur de ressources GUI:
<
FrameLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
SlidingDrawer
android
:
id
=
"
@+id/drawer
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
handle
=
"
@+id/handle
"
android
:
content
=
"
@+id/content
"
>
<
ImageView
android
:
id
=
"
@id/handle
"
android
:
layout_width
=
"
wrap_content
"
android
:
layout_height
=
"
wrap_content
"
android
:
src
=
"
@drawable/tray_handle_normal
"
/
>
<
Button
android
:
id
=
"
@id/content
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
text
=
"
Button
"
/
>
<
/
SlidingDrawer
>
<
/
FrameLayout
>
Code Java :
public
class
SlidingDrawerTuto extends
Activity {
@
Override
public
void
onCreate
(
Bundle icicle) {
super
.onCreate
(
icicle);
setContentView
(
R.layout.main);
//
Retrieve
the
SlidingDrawer
final
SlidingDrawer slidingDrawer =
(
SlidingDrawer) findViewById
(
R.id.sliding);
//
Listen
for
states
changed
slidingDrawer.setOnDrawerOpenListener
(
new
OnDrawerOpenListener
(
){
@
Override
public
void
onDrawerOpened
(
) {
//
Do
something,
for
example
change
background
picture:
slidingDrawer.getHandle
(
).setBackgroundResource
(
R.drawable.slidingOpen);
}
}
);
slidingDrawer.setOnDrawerScrollListener
(
new
OnDrawerScrollListener
(
) {
@
Override
public
void
onScrollStarted
(
) {
//
Do
something
}
@
Override
public
void
onScrollEnded
(
) {
//
Do
something
}
}
);
slidingDrawer.setOnDrawerCloseListener
(
new
OnDrawerCloseListener
(
) {
@
Override
public
void
onDrawerClosed
(
) {
//
Do
something
}
}
);
}
}
II. Méthodes de saisie : clavier physique ou logiciel▲
De manière transparente, Android propose le clavier logiciel (IME Input Method Editor) quand aucun clavier physique n'existe dans la manipulation de champs texte (EditorText). Nous verrons dans ce chapitre comment personnaliser ce comportement par défaut.
Depuis Android 1.5 un seul attribut sert à définir le style des champs EditText, android:inputType. Ces styles peuvent être séparés par un | de manière à se cumuler. La liste des inputTypes possibles est :
|
|
|
Ces inputTypes définissent le clavier qui apparaîtra lorsque l'utilisateur remplira le champ EditText ; ainsi, s'il est d'inputType number, le clavier n'aura que des chiffres…
Exemple :
<
TableLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
stretchColumns
=
"
1
"
>
<
TableRow
>
<
TextView
android
:
text
=
"
Aucune
regle
speciale
:
"
/
>
<
EditText
/
>
<
/
TableRow
>
<
TableRow
>
<
TextView
android
:
text
=
"
Adresse
email
:
"
/
>
<
EditText
android
:
inputType
=
"
text|textEmailAddress
"
/
>
<
/
TableRow
>
<
TableRow
>
<
TextView
android
:
text
=
"
Nombre
decimal
signe
:
"
/
>
<
EditText
android
:
inputType
=
"
number|numberSigned|numberDecimal
"
/
>
<
/
TableRow
>
<
TableRow
>
<
TextView
android
:
text
=
"
Date
:
"
/
>
<
EditText
android
:
inputType
=
"
date
"
/
>
<
/
TableRow
>
<
TableRow
>
<
TextView
android
:
text
=
"
Texte
multi-lignes
:
"
/
>
<
EditText
android
:
inputType
=
"
text|textMultiLine|textAutoCorrect
"
android
:
minLines
=
"
3
"
android
:
gravity
=
"
top
"
/
>
<
/
TableRow
>
<
/
TableLayout
>
La seconde préoccupation associée à ce clavier logiciel est de savoir ce que devient l'activité lorsque le clavier apparaît :
- Il peut pousser l'activité vers le haut quand il apparaît (mode adjustPan).
- Il peut modifier la taille de l'activité pour pouvoir se mettre à ses côtés sans rien changer d'autre (mode adjustResize).
- En mode paysage, il peut masquer l'activité et prendre tout l'écran pour améliorer la saisie.
Ce mode est choisi par Android (en fonction de votre layout), pour le modifier il faut le définir au niveau de l'activité, ce qui s'effectue dans le manifeste de cette activité :
<?
xml
version="1.0"
encoding="utf-8"?
>
<
manifest
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
package
=
"
com.commonsware.android.imf.two
"
android
:
versionCode
=
"
1
"
android
:
versionName
=
"
1.0
"
>
<
application
android
:
label
=
"
@string/app_name
"
android
:
icon
=
"
@drawable/icon
"
>
<
activity
android
:
name
=
"
.keyboardTuto
"
android
:
label
=
"
@string/app_name
"
android
:
windowSoftInputMode
=
"
adjustResize
"
>
<
intent-filter
>
<
action
android
:
name
=
"
android.intent.action.MAIN
"
/
>
<
category
android
:
name
=
"
android.intent.category.LAUNCHER
"
/
>
<
/
intent-filter
>
<
/
activity
>
<
/
application
>
<
/
manifest
>
Les modes disponibles sont :
- StateUnspecified (le système choisit l'état le plus approprié) ;
- stateUnchanged (le système laisse l'état du clavier en l'état quand l'activité passe au premier plan) ;
- stateHidden (le système cache le clavier quand l'activité passe au premier plan) ;
- stateAlwaysHidden (le système cache le clavier quoi qu'il arrive) ;
- stateVisible (le système affiche le clavier quand l'activité passe au premier plan) ;
- stateAlwaysVisible (le système affiche le clavier quoi qu'il arrive) ;
- adjustUnspecified (le système choisit comment le clavier s'insère dans votre activité) ;
- adjustResize (le système change la taille des composants de l'activité pour afficher le clavier) ;
- adjustPan (le système pousse votre activité pour afficher le clavier).
Ces modes sont cumulables les uns avec les autres avec l'opérateur « | » (ex : adjustResize|visible).
III. Les menus▲
Il y a deux types de menus : les menus contextuels et les menus d'option (menu usuel).
III-A. Menu d'option▲
Il se déclenche en appuyant sur un bouton de menu et a deux états : icône ou étendu. Il s'ouvre en mode icône (six icônes maximum avec le dernier qui vaut « + » pour afficher le reste du menu en mode étendu).
Deux façons d'implémenter un menu sont possibles : soit en Java, soit en XML.
La création s'effectue en surchargeant la méthode OnCreateOptionsMenu de l'activité:
@
Override
public
boolean
onCreateOptionsMenu
(
Menu menu) {
populateMenu
(
menu);
return
(
super
.onCreateOptionsMenu
(
menu));
}
L'objet menu est accessible directement dans les méthodes surchargées associées aux menus de l'activité.
Pour ajouter des choix et des sous-menus, il faut utiliser la méthode add de la classe Menu. Cette méthode possède quatre paramètres :
- Un identifiant de groupe permettant de regrouper un ensemble d'items en choix exclusif (comme ButtonGroup).
- Un identifiant de choix servant à identifier l'item du menu par un entier. Cet entier est récupéré par la méthode onOptionsItemSelected.
- Un identifiant d'ordre indiquant un emplacement du choix dans le menu lorsque ce dernier contient des options ajoutées par Android (utiliser Menu.NONE tant que vous ne maîtrisez pas cet attribut).
- Le texte à afficher par le menu.
Ce qui donne :
menu.add
(
Menu.NONE, ITEM1, Menu.NONE, "
Item
1
"
);
Les identifiants de choix et de groupes permettent ceci :
- MenuItem.setCheckable avec un identifiant de choix ajoute une case à cocher à côté du titre de l'item.
- Menu.SetGroupCheckable est identique à GroupButton pour les RadioButtons.
III-B. Menu contextuel▲
Le principe est identique au menu d'option. Le menu contextuel apparaît lorsqu'un utilisateur laisse appuyé un élément de la vue.
Les différences entre menu d'option et menu contextuel :
- Enregistrer les widgets qui porteront le menu contextuel en appelant la méthode registerForContextMenu et en passant le widget (une View).
- Implémenter la méthode OnContextMenu qui reçoit l'objet View en paramètre (ce qui permet d'implémenter plusieurs menus en fonction de cet objet). Cette méthode est appelée à chaque fois que le menu est affiché (contrairement au menu d'options).
Enfin la méthode OnContextItemSelected est partagée par tous les menus contextuels et ne reçoit qu'un MenuItem, il faut donc que les identifiants des items soient tous distincts pour tous les menus contextuels. De plus, getMenuInfo renvoie l'objet ContextMenu.ContextMenuInfo reçu par la méthode onCreateContextMenu.
III-C. Exemple▲
Descripteur d'IHM:
<
LinearLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
orientation
=
"
vertical
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
TextView
android
:
id
=
"
@+id/textView
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
android
:
text
=
"
Texte
multi-lignes
:
"
/
>
<
EditText
android
:
id
=
"
@+id/editText
"
android
:
inputType
=
"
text|textMultiLine|textAutoCorrect
"
android
:
minLines
=
"
3
"
android
:
gravity
=
"
top
"
/
>
<
/
LinearLayout
>
Code Java:
public
class
MenuTuto extends
Activity {
/**
*
A
text
view
*/
TextView textView;
/**
*
an
Edit
Text
*/
EditText editText;
//
Items
Identifier
used
by
the
option
menu
final
private
int
ITEM_ID1 =
Menu.FIRST +
100001
;
final
private
int
ITEM_ID2 =
Menu.FIRST +
100002
;
final
private
int
ITEM_ID3 =
Menu.FIRST +
100003
;
final
private
int
ITEM_ID4 =
Menu.FIRST +
100004
;
//
Item
used
by
the
Context
Menu
final
private
int
ITEM_ID5 =
Menu.FIRST +
100005
;
final
private
int
ITEM_ID6 =
Menu.FIRST +
100006
;
final
private
int
ITEM_ID7 =
Menu.FIRST +
100007
;
final
private
int
ITEM_ID8 =
Menu.FIRST +
100008
;
@
Override
public
void
onCreate
(
Bundle icicle) {
//
GUI
instanciation
super
.onCreate
(
icicle);
setContentView
(
R.layout.main);
//
Graphic
elements
creation
textView =
(
TextView) findViewById
(
R.id.textView);
editText =
(
EditText) findViewById
(
R.id.editText);
//
Adding
the
contextual
menu
on
the
Widget
EditText
registerForContextMenu
(
editText);
}
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/**
Context
Menu
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
//
Create
a
context
Menu
@
Override
public
void
onCreateContextMenu
(
ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
populateContextMenu
(
menu);
}
//
Link
the
context
menu's
items
selection
action
with
the
applyMenuChoice
method
@
Override
public
boolean
onContextItemSelected
(
MenuItem item) {
return
(
applyMenuChoice
(
item) |
|
super
.onContextItemSelected
(
item));
}
//
Fill
the
menu
private
void
populateContextMenu
(
Menu menu) {
menu.add
(
Menu.NONE, ITEM_ID5, Menu.NONE, getString
(
R.string.item5));
menu.add
(
Menu.NONE, ITEM_ID6, Menu.NONE, getString
(
R.string.item6));
menu.add
(
Menu.NONE, ITEM_ID7, Menu.NONE, getString
(
R.string.item7));
menu.add
(
Menu.NONE, ITEM_ID8, Menu.NONE, getString
(
R.string.item8));
}
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/**
Option
Menu
Methods
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
//
Create
an
option
Menu
@
Override
public
boolean
onCreateOptionsMenu
(
Menu menu) {
populateOptionMenu
(
menu);
return
(
super
.onCreateOptionsMenu
(
menu));
}
//
Link
the
option
menu's
items
selection
action
with
the
applyMenuChoice
method
@
Override
public
boolean
onOptionsItemSelected
(
MenuItem item) {
return
(
applyMenuChoice
(
item) |
|
super
.onOptionsItemSelected
(
item));
}
//
Fill
the
menu
private
void
populateOptionMenu
(
Menu menu) {
menu.add
(
Menu.NONE, ITEM_ID1, Menu.NONE, getString
(
R.string.item1));
menu.add
(
Menu.NONE, ITEM_ID2, Menu.NONE, getString
(
R.string.item2));
menu.add
(
Menu.NONE, ITEM_ID3, Menu.NONE, getString
(
R.string.item3));
menu.add
(
Menu.NONE, ITEM_ID4, Menu.NONE, getString
(
R.string.item4));
}
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/**
Option
and
Context
Menu
shared
Methods
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
//
Associated
action
method
when
a
selction
occurs
in
a
menu
private
boolean
applyMenuChoice
(
MenuItem item) {
//
Use
the
Item
identifier
to
know
the
selected
one
switch
(
item.getItemId
(
)) {
case
ITEM_ID1:
case
ITEM_ID2:
case
ITEM_ID3:
case
ITEM_ID4:
textView.setText
(
"
The
item
selected
from
the
option
Menu
is:
"
+
item.getTitle
(
));
break
;
case
ITEM_ID5:
case
ITEM_ID6:
case
ITEM_ID7:
case
ITEM_ID8:
editText.append
(
"
\r\nThe
item
selected
from
the
context
Menu
is:
"
+
item.getTitle
(
));
break
;
}
return
(
false
);
}
}
III-D. Utilisation de l'inflation pour les menus (description via fichier XML d'un menu)▲
L'élément racine doit se nommer Menu, ses fils sont de type « item » ou « group ». Les sous-menus sont déclarés comme étant des menus contenus par un item. Tous les items ont un identifiant permettant de les manipuler dans le code Java.
Exemple, le fichier res\menu\sample :
<
menu
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
>
<
item
android
:
id
=
"
@+id/item2
"
android
:
orderInCategory
=
"
2
"
android
:
title
=
"
item2_no_icon
"
/
>
<
item
android
:
id
=
"
@+id/item3
"
android
:
title
=
"
Item3_icon
"
android
:
orderInCategory
=
"
3
"
android
:
icon
=
"
@drawable/icon
"
/
>
<
item
android
:
id
=
"
@+id/item4
"
android
:
orderInCategory
=
"
4
"
android
:
enabled
=
"
false
"
android
:
title
=
"
item4_disable
"
/
>
<
group
android
:
id
=
"
@+id/itemGroup1
"
android
:
menuCategory
=
"
secondary
"
android
:
visible
=
"
false
"
>
<
item
android
:
id
=
"
@+id/itemGroup1_item1
"
android
:
orderInCategory
=
"
0
"
android
:
title
=
"
item
1.1
"
/
>
<
item
android
:
id
=
"
@+id/itemGroup1_item2
"
android
:
orderInCategory
=
"
1
"
android
:
title
=
"
item1.2
"
/
>
<
/
group
>
<
item
android
:
id
=
"
@+id/submenu1
"
android
:
orderInCategory
=
"
3
"
android
:
title
=
"
submenu
"
>
<
menu
>
<
item
android
:
id
=
"
@+id/submenu_item1
"
android
:
title
=
"
Item_s1_shown
"
android
:
visible
=
"
true
"
android
:
alphabeticShortcut
=
"
s
"
/
>
<
item
android
:
id
=
"
@+id/submenu_item2
"
android
:
title
=
"
Item_s2_hidden
"
android
:
visible
=
"
false
"
android
:
alphabeticShortcut
=
"
h
"
/
>
<
/
menu
>
<
/
item
>
<
/
menu
>
L'ordre du choix des menus est celui de leur déclaration au sein de ce fichier. Les tags disponibles pour les menus sont :
- titre (label de l'item) ;
- icône (icône de l'item) ;
- ordre (pour spécifier un ordre autre que celui de la déclaration des items) ;
- activation (android:enable) se manipule en Java avec setEnable (pour un item) ou setGroupEnable (pour un groupe) ;
- visibilité (android:visible) se manipule en Java avec setVisible ;
- les raccourcis (android:alphabeticsShortCut ou android:numericalShortCut).
Le descripteur d'IHM :
<
LinearLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
orientation
=
"
vertical
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
TextView
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
wrap_content
"
android
:
text
=
"
Menu
Avaialable
"
/
>
<
/
LinearLayout
>
Et le code Java :
public
class
MenuXmlTuto extends
Activity {
/**
*
the
Menu
of
the
activity
*/
private
Menu theMenu =
null
;
//
Création
de
l'activité
(qui
n'est
qu'un
TextView
;
un
label
quoi)
@
Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.main);
}
//
Création
du
menu
d'options
associé
au
fichier
xml
res\menu\sample
@
Override
public
boolean
onCreateOptionsMenu
(
Menu menu) {
//
instanciation
du
menu
via
le
fichier
XML
new
MenuInflater
(
getApplication
(
)).inflate
(
R.menu.sample, menu);
//
the
menu
et
menu
sont
le
même
objet
theMenu =
menu;
//
Création
du
menu
comme
avant
return
(
super
.onCreateOptionsMenu
(
menu));
}
//
Instanciation
de
l'action
associée
à
la
sélection
d'un
item
du
menu
(mets
à
jour
le
TextView
//
avec
le
message
associé
à
l'item)
@
Override
public
boolean
onOptionsItemSelected
(
MenuItem item) {
//
Do
something:
//
for
exemple:
if
(
item.getItemId
(
)=
=
R.id.submenu_item1){
//
show/hide
the
hidden
item
theMenu.setGroupVisible
(
R.id.itemGroup1,
!
theMenu.findItem
(
R.id.itemGroup1).isVisible
(
));
//
show
hide
an
item
theMenu.findItem
(
R.id.item4).setVisible
(
true
);
}
else
if
(
item.getItemId
(
)=
=
R.id.item3){
//
Enable/disable
an
item
theMenu.findItem
(
R.id.item4).setEnabled
(
true
);
//
enable/disable
a
group
theMenu.setGroupEnabled
(
R.id.itemGroup1, false
);
}
return
(
super
.onOptionsItemSelected
(
item));
}
}
IV. Polices de caractères▲
Trois polices logiques sont disponibles : « sans », « mono » et « sheriff ».
Pour cela dans un TextView (tous les widgets héritent de TextView !!), il faut utiliser l'attribut @android:typeface.
Exemple :
<
TableLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
android
:
stretchColumns
=
"
1
"
>
<
TableRow
>
<
TextView
android
:
id
=
"
@+id/sans
"
android
:
text
=
"
Hello
sans
"
android
:
typeface
=
"
sans
"
android
:
textSize
=
"
20sp
"
/
>
<
/
TableRow
>
<
TableRow
>
<
TextView
android
:
id
=
"
@+id/serif
"
android
:
text
=
"
Hello
serif
"
android
:
typeface
=
"
serif
"
android
:
textSize
=
"
20sp
"
/
>
<
/
TableRow
>
<
TableRow
>
<
TextView
android
:
id
=
"
@+id/monospace
"
android
:
text
=
"
Hello
monospace
"
android
:
typeface
=
"
monospace
"
android
:
textSize
=
"
20sp
"
/
>
<
/
TableRow
>
<
/
TableLayout
>
Ajouter une police.
Il suffit de créer un répertoire assets/polices dans ressources et de copier les polices de caractères au format TTF (True Type).
Puis en Java, affecter cette police aux widgets :
TextView tv=(TextView)findViewById(R.id.custom);
Typeface face=Typeface.createFromAsset(getAssets(),"fonts/HandmadeTypewriter.ttf");
tv.setTypeface(face);
Attention : les polices pèsent, ne pas trop ajouter de polices sous peine de pénaliser le téléphone en lui volant toute sa mémoire (une police peut aller de 70Ko à plus de 500Ko !!!).
V. Intégrer le navigateur WebKit à une activité : le widget WebView▲
Ce navigateur possède son propre package (android.webkit). Pour les opérations simples, WebKit est comme un autre widget Android. On l'affiche, on lui passe l'URL qu'il doit afficher et il l'affiche :
<
LinearLayout
xmlns
:
android
=
"
http://schemas.android.com/apk/res/android
"
android
:
orientation
=
"
vertical
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
>
<
WebView
android
:
id
=
"
@+id/webkit
"
android
:
layout_width
=
"
fill_parent
"
android
:
layout_height
=
"
fill_parent
"
/
>
<
/
LinearLayout
>
Et le code Java :
public
class
WebKitTutoSimple extends
Activity {
WebView browser;
@
Override
public
void
onCreate
(
Bundle icicle) {
super
.onCreate
(
icicle);
setContentView
(
R.layout.main);
browser =
(
WebView) findViewById
(
R.id.webkit);
//
load
an
URL
browser.loadUrl
(
"
http://stinfoservices.net/
"
);
//
Set
javascript
enable
browser.getSettings
(
).setJavaScriptEnabled
(
true
);
//
Javascript
can
open
a
new
window
browser.getSettings
(
).setJavaScriptCanOpenWindowsAutomatically
(
true
);
}
}
V-A. Activation JavaScript▲
Par défaut il est désactivé. Pour l'activer :
//
Set
JavaScript
enable
browser.getSettings
(
).setJavaScriptEnabled
(
true
);
//
Javascript
can
open
a
new
window
browser.getSettings
(
).setJavaScriptCanOpenWindowsAutomatically
(
true
);
V-B. La méthode LoadData▲
Au lieu de faire charger une URL, il est possible de charger des données HTML qui seront affichées au sein du navigateur.
//
or
load
data
browser.loadData
(
"
<html><body>Bonjour
!</body></html>
"
,"
text/html
"
, "
UTF-8
"
);
V-C. Méthodes de navigation▲
Pour des raisons d'ergonomie, WebView ne possède pas de barre de navigation. Mais les méthodes pour naviguer existent (au développeur d'inventer son IHM associée). Ces méthodes sont :
- reload() ;
- goBack() (pour revenir en arrière) et canGoBack (pour savoir si la page précédente existe) ;
- goFroward() et canForward (idem mais pour le forward) ;
- goBackOrForward(int step) avance ou recule du nombre de pas désignés dans l'historique des pages (-1 => goBack) ;
- clearCache ;
- clearHistory.
VI. Messages surgissants : Toast et AlertDialog▲
VI-A. Toast▲
Le toast est un message évanescent qui s'affiche et disparaît de lui-même. Il laisse le focus où il est déjà.
Pour lancer un toast, il suffit de trois paramètres : activité courante (le contexte), le texte à afficher ainsi que la durée qui vaut Length_Long ou Length_Short:
//
Dans
le
cas
où
l'on
doit
récupérer
le
contexte
de
l'application
(en
dehors
d'une
activité)
Toast.makeText
(
getApplicationContext
(
), "
A
toast
"
, Toast.LENGTH_LONG).show
(
);
//
Dans
le
cas
où
l'on
se
trouve
dans
une
activité,
this=getApplicationContext
Toast.makeText
(
this
, "
A
toast
"
, Toast.LENGTH_SHORT).show
(
);
VI-B. Les AlertDialogs▲
Pour créer une AlertDialog il faut utiliser le builder et chaîner les appels (car les méthodes de builder renvoient builder, pas bête !) ou définir les attributs de la fenêtre proprement sur l'objet builder:
//
Define
the
AlertDialog
(android.app.AlertDialog.Builder;)
Builder alertDialog=
new
AlertDialog.Builder
(
this
);
//
set
its
title
alertDialog.setTitle
(
"
The
Alert
Dialog
Title
"
);
//
set
its
message
alertDialog.setMessage
(
"
The
message
to
display
"
);
//
Define
its
neutral
button
(its
label
and
the
associated
action)
alertDialog.setNeutralButton
(
"
My
neutral
Button
"
,
new
DialogInterface.OnClickListener
(
) {
public
void
onClick
(
DialogInterface dlg, int
sumthin) {
//
Do
something.
//
if
nothing
done,
the
window
will
just
close
}
}
);
//
Define
its
positive
button
(its
label
and
the
associated
action)
alertDialog.setPositiveButton
(
R.string.positiveButton, new
DialogInterface.OnClickListener
(
) {
public
void
onClick
(
DialogInterface dlg, int
sumthin) {
//
Do
something.
//
if
nothing
done,
the
window
will
just
close
}
}
);
//
Define
its
negative
button
(its
label
and
the
associated
action)
alertDialog.setNegativeButton
(
"
No
"
, new
DialogInterface.OnClickListener
(
) {
public
void
onClick
(
DialogInterface dlg, int
sumthin) {
//
Do
something.
//
if
nothing
done,
the
window
will
just
close
}
}
);
//
show
the
alert
alertDialog.show
(
);
VII. Android2EE: La Formation et l'Expertise Android à votre service▲
Android2EE
|
|
|
VIII. Récupération des tutoriels et lecture des autres chapitres du livre▲
Vous pouvez lire l'ensemble de l'ouvrage sur Android2EE, à cet adresse Livre en consultation. Les 28 chapitres sont disponibles. Un tutorial sera bientôt disponible sur le site Android2EE.
IX. Articles, conférences et autres tutoriaux made in Android2EE▲
Vous pouvez trouver d'autres articles sur developpez.com rédigés par Android2EE.
Vous pouvez trouver les projets Android open sources d'Android2EE sur GitHub.
Android2EE sur Github |
GDirectionsApiUtils pour vous simplifiez l'utilisation du service REST Google Api Direction (les itinéraires entre deux points). Le MythicServiceHelper est un projet simplifiant la communication entre les services et les activités. Il est mieux d'utiliser, à l'heure d'aujourd'hui, EventBus ou Otto. Vous pouvez aller le voir quand même par curiosité. Le Bluetooth avec Android expliqué. Ce projet est un chat bluetooth qui vous montre, par l'exemple, comment mettre en place une communication BlueTooth entre deux appareils Android. Le projet ForecastYahooRest a pour objectif de vous expliquer comment mettre une architecture saine pour vos projets Android pour effectuer des appels REST. Ce projet est lié à la conférence "An Android Journey" que vous pouvez retrouver sur Android2ee. Le projet SignInWithGoogleTutorialvous explique comment mettre l'authentification Google au sein de vos applications. Il est lié à la conférence Google Sign In que vous pouvez retrouver sur Android2EE. |
Vous pouvez trouver les supports des conférences d'Android2EE sur SlideShared.
Android2EE sur SlideShare |
Retrouvez la liste des tutoriaux Android2EE de la formation complète. C'est pas ma meilleure conférence :) An Android Journey La conférence 2014 d'Android2EE qui vous donne toutes les astuces, les bonnes pratiques et les bons conseils à mettre en place dans vos applications pour en faire des applications exceptionnelles. ActionBarCompat Cette conférence vous explique comment mettre en place l'ActionBar dans vos applications pour toutes les versions du système en utilisant l'ActionBarCompat. GoogleSignIn L'authentification Google vous est expliquée dans cette conférence. Android ProTips Cette conférence a été donnée à la DroidCon Paris 2013 pour vous présenter les meilleurs conseils sur le développement Android donnée aux GoogleIo. Ce sont mes bonnes pratiques favorites. Architecture Android Une peu d'architecture, ça vous dit? Cette conférence est dédiée à l'architecture, quels sont les problèmes rencontrés et les bonnes pratiques à mettre en place. Android, un nouveau futur s'ouvre à nous Cette conférence, donnée à Brazzaville, présente les enjeux de la mobilité et en particulier ma vision du futur relative à Android. Combining the power of Eclipse with Android Cette conférence, donnée à l'EclipseDay 2012, présente comment utiliser la DDMS et chasser les fuites mémoires au sein de vos applications Android. A Quick OverviewCette conférence, donnée au CocoHeads Toulouse en 2012, est une introduction à la programmation Android. Android A Quick Course @DevoxxFr Cette présentation est un extraie de la conférence "Android A Quick Course", donnée à DevoxxFrance, pour apprendre le développement Android. Les vidéos (3 heures tout de même sont disponibles sur le site Android2EE ou sur Parleys) |
Les vidéos de certaines de ces conférences sont disponibles à l'adresse suivante : Les vidéos
X. Le site Android2ee, une référence pour le développement Android.▲
Le site Android2EE vous propose des tutoriels, des articles, des vidéos, des conférences, des eBooks en libre consultation pour monter en compétence sur la technologie Android.
Vous trouverez tout cela dans la partie « Open Resources ».
N'hésitez plus visitez-le ! Android2EE
XI. Android2ee vous présente l'Ebook de programmation Android▲
Le nouveau système d'exploitation de Google pour les téléphones portables et les nouvelles tablettes est là. Sa réputation est solide, il envahit le monde de la téléphonie, il est ouvert et offre des outils de développement Java au monde des programmeurs. Il ouvre les portes du développement mobile à tous les développeurs objets avec un coût minime pour la montée en compétence. Une seule question se pose :
Êtes-vous prêts ?
L'objectif de ces livres est très clair : vous permettre en un temps record d'être autonome en programmation Android. Si vous êtes un programmeur Java (débutant ou confirmé), le but est que vous soyez autonome en moins de dix jours. C'est cet objectif qui est à l'origine de ce livre, permettre aux collaborateurs de mon entreprise de monter en compétence sur cette technologie avec rapidité et efficience. Vous serez alors à même de concevoir une application, de l'implémenter, de la tester, de l'internationaliser et de la livrer à votre client.
Lancez-vous dans la programmation Android et faites-vous plaisir !
Vous serez aussi capable de connaître et comprendre quelles sont les considérations à avoir lorsque l'on a à charge une application Android en tant que professionnel de l'informatique. Quelle est la stratégie de tests à utiliser ? Comment signer son application ? Comment la déployer ? Comment mettre en place la gestion du cycle de vie de l'application ? Comment implémenter l'intégration continue ?
Soyez efficient dans l'encadrement de vos projets Android d'entreprise.
L'achat d'un EBook vous donne accès à l'ensemble des tutoriaux Android2EE, plus de 50 projets Android qui vous apprendrons à mettre en place une notion spécifique (SlidingDrawer, Parsing d'un service REST, Mise en place d'un service, d'un ContentProvider...). Vous pouvez dès maintenant vous lancer dans la programmation Android, n'hésitez pas faîtes vous plaisir, il y a 75% de réduction sur les EBooks en ce moment:
Apprendre la programmation Android avec les EBooks Android2EE |
Android, A Complete Course, From Basics To Enterprise Edition (fr). Android, A Quick Course (fr). Android, An Entreprise Edition Vision (fr). Les eBooks sont disponibles en français et en anglais, à votre convenance. |
Nota Bene: l'ouvrage "Android, A Complete Course, From Basics To Enterprise Edition" réunit, au sein d'un même document, les livres "Android, A Quick Course" et "Android, An Enterprise Edition Vision" permettant au lecteur d'avoir dans un même document la totalité des préoccupations liées à la mise en place de projets Android, de la montée en compétence en tant que développeur à la gestion du cycle de vie du projet.