I. Filtres d'intentions▲
I-A. Objectif des intentions et bonne pratique▲
Les applications Android doivent se décomposer en activités distinctes les unes des autres. Au sein de ces applications, les activités doivent pouvoir s'enchaîner, s'appeler, retourner à leur activité principale. Pour mettre en place cette communication entre activités, Android utilise le système des intentions. Celles-ci permettent d'envoyer des messages d'une activité vers une autre avec des données pour les activer.
Dans ce contexte, il faut se demander si l'activité mère, quand elle lance une autre activité, est dans une relation maître-esclave ou dans une relation de pair à pair.
Dans le premier cas, l'activité mère attend que l'activité fille finisse et est informée de cette fin. Dans l'autre cas, l'activité fille est lancée, l'activité mère n'a plus de contact avec elle.
I-B. Définition▲
Une intention peut se traduire par « je veux, toi système, que tu fasses… ». Et cela dépend de l'action demandée et du contexte. Il faut les considérer comme de la colle entre activités permettant de les lier les unes aux autres.
Une intention est ainsi une action associée à des données. Les actions sont des constantes : ACTION_VIEW, ACTION_EDIT, ACTION_PICK, les données sont des URI.
Les intentions peuvent se spécifier ; on peut leur rajouter des informations :
- Une catégorie : LAUNCHER (pour les activités présentes dans le lanceur Android), DEFAULT ou ALTERNATIVE.
- Un type MIME : indique le type de la ressource (comme pour les mails).
- Un composant : indique la classe d'activité censée recevoir l'intention. Cette méthode n'est pas la plus heureuse, car elle fige l'activité associée. Soit vous l'avez codée vous-même, dans ce cas, c'est naturel, sinon, l'utilisation des autres paramètres est préconisée.
- Des « extras » : un bundle d'informations permettant de transférer des données à l'activité cible.
I-C. Routage des intentions▲
Il est préférable d'utiliser les URI et le type MIME, plutôt que Composant si vous souhaitez dialoguer avec une application qui n'est pas la vôtre. En d'autres termes, laissez Android se charger de trouver l'activité cible.
Pour qu'une activité soit éligible au routage d'une intention, il faut qu'elle supporte :
- l'action indiquée ;
- le type MIME indiqué ;
- ainsi que la catégorie.
Il faut donc spécifier suffisamment pour permettre à Android de trouver votre activité cible.
I-C-1. Déclarer des intentions▲
Les déclarations se déclarent dans le fichier manifest.xml de l'application.
Pour être éligible, une activité doit ainsi déclarer les intentions auxquelles elle souhaite répondre, typiquement, pour une activité qui se lance par l'IHM principale d'Android, on rajoute :
2.
3.
4.
<intent-filter>
<action
android
:
name
=
"android.intent.action.MAIN"
/>
<category
android
:
name
=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
Un autre exemple plus utile est la déclaration d'une intention qui n'est pas main launcher :
2.
3.
4.
5.
6.
7.
<intent-filter>
<action
android
:
name
=
"android.intent.action.VIEW"
/>
<action
android
:
name
=
"android.intent.action.EDIT"
/>
<action
android
:
name
=
"android.intent.action.PICK"
/>
<category
android
:
name
=
"android.intent.category.DEFAULT"
/>
<data
mimeType
:
name
=
"vnd.android.cursor.dir/vnd.google.note"
/>
</intent-filter>
Cette intention déclare pouvoir répondre aux actions de visualisation et d'édition associées à un objet de type vnd.android.cursor.dir/vnd.google.note (c'est l'URI de la définition de l'objet). De même, le PICK permet de récupérer l'un de ces objets et de retourner dans l'application appelante. (Cf. http://developer.android.com/reference/android/content/Intent.html pour l'exemple complet).
Les intentions peuvent ainsi, en interne de l'application, faire des appels entre ces sous-modules. Ou en termes Android, les intentions permettent d'appeler différentes activités au sein de votre application de manière transparente.
I-C-2. Récepteur d'intention▲
Typiquement, au lieu de recevoir une intention avec une activité, il peut être utile d'implémenter au sein de l'application une classe spécifique qui s'occupe de la récupération des intentions (comme un service) et de leur traitement qui peut être, du coup, contextuel (appel à un service, à plusieurs activités…).
Pour cela, il suffit de faire étendre votre classe réceptrice de la classe BroadCastReceiver et la déclarer dans le manifest.xml par :
<receiver android
:
name
=
"maClasseReceptionniste"
/>
Cette classe doit étendre la méthode onReceive. De plus, elle ne vit que lors de la réception d'une intention, elle est créée à la réception et détruite dès que la méthode onReceive est terminée. Ainsi, la classe BroadcastReceiver ne peut être liée à un service, une fenêtre de dialogue ou quoi que ce soit d'autre n'appartenant pas à son thread.
La seule exception à cette règle est quand votre classe qui hérite de BroadCastReceiver est implémentée par un composant d'une durée de vie longue (un service, une activité), dans ce cas, elle sera détruite quand l'hôte (bref le service, l'activité) est détruite.
Dans ce cas, le receveur ne se déclare pas dans le manifest.xml, il faut appeler la méthode registerReceiver dans le code de votre activité (service) au sein de la méthode onResume() et unregisterReceiver dans la méthode onPause().
Seuls les récepteurs actifs peuvent recevoir des intentions…
I-D. Lancer des activités▲
I-D-1. Instanciation▲
Pour instancier une activité interne à son programme :
final
Intent intent =
new
Intent
(
).setClass
(
this
, MyDaughterActivity.class
);
Cette instruction déclare une intention associée à l'activité MyDaughterActivity qui est une classe de votre programme et this qui est l'activité courante.
Pour instancier une activité externe à votre programme, il vaut mieux spécifier une URI et une action, par exemple :
2.
3.
4.
5.
6.
7.
// Retrieve latitude and longitude
String latitude =
"43.565715431592736"
;
String longitude =
"1.398482322692871"
;
// Format the associated uri
Uri uriGeo =
Uri.parse
(
"geo:"
+
latitude +
","
+
longitude);
// Declare the associated Intent
final
Intent intentGeo =
new
Intent
(
Intent.ACTION_VIEW, uriGeo);
Cette intention demande au système d'afficher une URI de type géo, à lui de se débrouiller pour trouver quelle activité répondra à cette intention.
I-D-2. Appel▲
Pour lancer une activité, deux cas s'offrent à vous, le cas de la relation pair-à-pair ou le cas maître-esclave entre vos deux activités.
Dans le cas pair-à-pair (c.-à-d. l'activité mère lance l'activité fille et n'attend rien) :
startActivity
(
intentGeo);
Dans le cas maître-esclave :
startActivityForResult
(
intentContactForResult, INTENT_CALL_ID);
Il faut alors implémenter dans l'activité mère la méthode onActivityResult qui est appelée lorsque l'activité fille prend fin. L'activité fille, elle, doit implémenter la méthode setResult() qui généralement renvoie RESULT_OK ou RESULT_CANCELLED.
On peut récupérer aussi dans onActivityResult un String contenant des informations (une URL par exemple) ou un objet Bundle.
I-D-2-a. Exemple▲
Dans cet exemple, nous montrons comment lancer :
- une activité qui appartient à votre programme ;
- une activité qui permet de se géolocaliser avec une latitude/longitude grâce à la carte ;
- une activité qui récupère un contact et affiche les informations associées.
Ce projet est donc séparé en deux classes :
- l'activité principale qui lance les autres activités et qui implémente onActivityResult pour traiter les activités lancées avec la méthode startActivityForResults ;
- l'activité otherActivity qui ne fait qu'afficher un champ texte.
Le code Java de la classe principale :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
public
class
IntentionSimpleTuto extends
Activity {
// The unique identifier for the call using Intent of contact
private
final
int
INTENT_CALL_ID =
10012220
;
@Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.main);
// To launch your own activity
// First declare an intent
final
Intent intent =
new
Intent
(
).setClass
(
this
, OtherActivity.class
);
// Then add the action to the button:
Button btnOtherActivity =
(
Button) findViewById
(
R.id.launchOther);
btnOtherActivity.setOnClickListener
(
new
View.OnClickListener
(
) {
public
void
onClick
(
View v) {
// Launch the activity
startActivity
(
intent);
}
}
);
// Do the same for Geo*
// Retrieve latitude and longitude
String latitude =
"43.565715431592736"
;
String longitude =
"1.398482322692871"
;
// Format the associated uri
Uri uriGeo =
Uri.parse
(
"geo:"
+
latitude +
","
+
longitude);
// Declare the associated Intent
final
Intent intentGeo =
new
Intent
(
Intent.ACTION_VIEW, uriGeo);
// instanciate the button
Button btnGeoActivity =
(
Button) findViewById
(
R.id.launchGeo);
btnGeoActivity.setOnClickListener
(
new
View.OnClickListener
(
) {
public
void
onClick
(
View v) {
// Launch the activity
startActivity
(
intentGeo);
}
}
);
// Do the same for Contact waiting for result
// Format the associated uri
Uri uriContact =
Uri.parse
(
"content://contacts/people"
);// "content://contacts/people"
// Declare the intent:
final
Intent intentContactForResult =
new
Intent
(
Intent.ACTION_PICK,
uriContact);
// instanciate the button
Button btnContactActivityForResults =
(
Button) findViewById
(
R.id.launchContactForResult);
btnContactActivityForResults
.setOnClickListener
(
new
View.OnClickListener
(
) {
public
void
onClick
(
View v) {
// Launch the activity
startActivityForResult
(
intentContactForResult,
INTENT_CALL_ID);
}
}
);
}
/*
* * (non-Javadoc) * * @see android.app.Activity#onActivityResult(int, int,
* android.content.Intent)
*/
@Override
protected
void
onActivityResult
(
int
requestCode, int
resultCode, Intent data) {
super
.onActivityResult
(
requestCode, resultCode, data);
if
(
requestCode ==
INTENT_CALL_ID) {
if
(
resultCode ==
Activity.RESULT_OK) {
Uri contactData =
data.getData
(
);
Toast.makeText
(
IntentionSimpleTuto.this
,
"Result ok (uri:"
+
contactData +
") data "
+
contactData.toString
(
), Toast.LENGTH_LONG)
.show
(
);
Cursor c =
managedQuery
(
contactData, null
, null
, null
, null
);
StringBuffer columnName =
new
StringBuffer
(
"Result : "
);
String value;
String name =
"..."
;
if
(
c.moveToFirst
(
)) {
for
(
int
i =
0
; i <
c.getColumnCount
(
); i++
) {
value =
c.getString
(
c.getColumnIndexOrThrow
(
c
.getColumnName
(
i)));
columnName.append
(
",
\r\n
"
+
c.getColumnName
(
i) +
": "
+
value);
}
Toast.makeText
(
IntentionSimpleTuto.this
, columnName,
Toast.LENGTH_LONG).show
(
);
name =
c.getString
(
c
.getColumnIndexOrThrow
(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
Toast.makeText
(
IntentionSimpleTuto.this
,
"Et le nom : "
+
name, Toast.LENGTH_LONG).show
(
);
}
}
else
if
(
resultCode ==
Activity.RESULT_CANCELED) {
Toast.makeText
(
IntentionSimpleTuto.this
,
"Result ko no contact picked"
, Toast.LENGTH_LONG)
.show
(
);
}
}
}
}
Le code Java de la seconde activité :
2.
3.
4.
5.
6.
7.
8.
public
class
OtherActivity extends
Activity {
/** Called when the activity is first created. */
@Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.other_activity);
}
}
Le mainLayout.xml de l'activité principale qui déclare trois boutons et un champ texte :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
<?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"
>
<TextView
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/hello"
>
</TextView>
<Button
android
:
text
=
"@string/launchOther"
android
:
id
=
"@+id/launchOther"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
>
</Button>
<Button
android
:
text
=
"@string/launchGeo"
android
:
id
=
"@+id/launchGeo"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
>
</Button>
<Button
android
:
text
=
"@string/launchContactForResult"
android
:
id
=
"@+id/launchContactForResult"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
>
</Button>
</LinearLayout>
Le layout de other_activity.xml :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
<?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"
>
<TextView
android
:
id
=
"@+id/otherTextView"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
text
=
"@string/otheractivity"
/>
</LinearLayout>
Le fichier des chaînes de caractères (string.xml) :
2.
3.
4.
5.
6.
7.
8.
9.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string
name
=
"hello"
>
Hello World, IntentionSimpleTuto!</string>
<string
name
=
"app_name"
>
IntentionSimpleTuto</string>
<string
name
=
"launchOther"
>
Launch the activity other</string>
<string
name
=
"launchGeo"
>
Launch the activity Geo</string>
<string
name
=
"launchContactForResult"
>
Launch the activity Contact for results</string>
<string
name
=
"otheractivity"
>
And an other activity appears in front of your amazed eyes !</string>
</resources>
Et le fichier manifest.xml :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
package
=
"net.stinfoservices.android.tuto.core"
android
:
versionCode
=
"1"
android
:
versionName
=
"1.0"
>
<application
android
:
icon
=
"@drawable/icon"
android
:
label
=
"@string/app_name"
>
<activity
android
:
name
=
".IntentionSimpleTuto"
android
:
label
=
"@string/app_name"
>
<intent-filter>
<action
android
:
name
=
"android.intent.action.MAIN"
/>
<category
android
:
name
=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<activity
android
:
name
=
"OtherActivity"
></activity>
</application>
<uses-sdk
android
:
minSdkVersion
=
"8"
/>
<uses-permission
android
:
name
=
"android.permission.READ_CONTACTS"
></uses-permission>
</manifest>
I-E. Cas particulier : la navigation par onglets▲
Pour des raisons de sécurité, une activité ne peut héberger les activités d'autres applications au sein de ses onglets. Ainsi, pour obtenir une navigation par onglet, il faut tout d'abord créer l'activité contenante qui est une TabActivity et lui rajouter des onglets que l'on peuple avec des intentions. Pour cela, on récupère le TabHost de la classe TabActivity et pour chacun des onglets on effectue les opérations suivantes :
- définition de l'Intent qui représente l'activité contenue par l'onglet ;
- récupération puis définition du TabSpec (son tag, son label, son contenu via l'Intent) ;
- ajout du TabSpec au TabHost.
Le code Java de la classe principale :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
public
class
MultiTabBrowserTuto extends
TabActivity {
/** Called when the activity is first created. */
@Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
// Define the Tab structure
setContentView
(
R.layout.main);
// Retrieve the ressource to access to the icon
Resources resources =
getResources
(
); // Resource object to get
// Drawables
// Set the tabHost (set it has final to use it in the
// OnTabChangeListener)
final
TabHost tabHost =
getTabHost
(
);
// Define the tabSpec that can be thought has the content of the
// TabPanel
TabHost.TabSpec tabSpec;
// Define the intent that is used to populate the tabSpec
Intent intent;
// Create an Intent to launch an Activity for the tab
intent =
new
Intent
(
).setClass
(
this
, SiteWebSTI.class
);
// Initialize a TabSpec for each tab and add it to the TabHost
// Get a new TabHost.TabSpec associated with this tab host.
tabSpec =
tabHost.newTabSpec
(
"SiteWebSti"
);
// Define its indicator the label displayed (it should be
// ressources.getString(R.string.stringId)
tabSpec.setIndicator
(
"SiteSti"
,
resources.getDrawable
(
R.drawable.ic_tab));
// Define the content of the Spec (the TabPanel)
tabSpec.setContent
(
intent);
// Add it to the tab container
tabHost.addTab
(
tabSpec);
// Do the same with the tab that displays a simple TextView:
// Define the intent that will be displayed
intent =
new
Intent
(
).setClass
(
this
, TextViewActivity.class
);
// Get a new TabHost.TabSpec associated with this tab host.
tabSpec =
tabHost.newTabSpec
(
"textView"
);
// Define its indicator the label displayed (it should be
// ressources.getString(R.string.stringId)
tabSpec.setIndicator
(
"TextView"
,
resources.getDrawable
(
R.drawable.ic_tab));
// Define the content of the Spec (the TabPanel)
tabSpec.setContent
(
intent);
// Add it to the tab container
tabHost.addTab
(
tabSpec);
// Do the same with the tab that displays a simple Clock (analogic and
// digital):
// Define the intent that will be displayed
intent =
new
Intent
(
).setClass
(
this
, ClockAD.class
);
// Get a new TabHost.TabSpec associated with this tab host.
tabSpec =
tabHost.newTabSpec
(
"clock"
);
// Define its indicator the label displayed
tabSpec.setIndicator
(
"Clock"
, resources.getDrawable
(
R.drawable.ic_tab));
// Define the content of the Spec (the TabPanel)
tabSpec.setContent
(
intent);
// Add it to the tab container
tabHost.addTab
(
tabSpec);
// Define the current tab displayed (here the clock)
tabHost.setCurrentTab
(
2
);
// Add a listener that just displays a Toast with the tag of the new
// selected tab
tabHost.setOnTabChangedListener
(
new
OnTabChangeListener
(
) {
@Override
public
void
onTabChanged
(
String tabId) {
Toast.makeText
(
getApplicationContext
(
),
"New tab selection : "
+
tabHost.getCurrentTabTag
(
),
Toast.LENGTH_SHORT).show
(
);
}
}
);
}
}
Les codes Java des classes des activités sont des codes d'activités normales. Les classes ne savent pas qu'elles vont être utilisées au sein d'onglets.
Le code Java de la classe SiteWebSti qui ne fait que déclarer un WebKit qui pointe vers un site :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
public
class
SiteWebSTI extends
Activity {
WebView browser;
@Override
public
void
onCreate
(
Bundle icicle) {
super
.onCreate
(
icicle);
browser =
new
WebView
(
this
);
setContentView
(
browser);
browser.loadUrl
(
"http://www.stinfoservices.net/"
);
}
}
Le code Java de la classe TextView qui ne fait que déclarer un TextView avec un texte simple :
2.
3.
4.
5.
6.
7.
8.
9.
public
class
TextViewActivity extends
Activity {
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
TextView textview =
new
TextView
(
this
);
textview.setText
(
"Hello Guy this a TabPanel also called TabSpec"
);
setContentView
(
textview);
}
}
Le code Java de la classe ClockAD qui ne fait que charger son fichier de layout.xml nommé clock.xml :
2.
3.
4.
5.
6.
7.
8.
public
class
ClockAD extends
Activity {
/** Called when the activity is first created. */
@Override
public
void
onCreate
(
Bundle savedInstanceState) {
super
.onCreate
(
savedInstanceState);
setContentView
(
R.layout.clock);
}
}
Le fichier de layout associé à la classe ClockAD qui se nomme clock. Il déclare deux éléments, une horloge digitale et une analogique :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
orientation
=
"vertical"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
>
<AnalogClock
android
:
id
=
"@+id/analog"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"wrap_content"
android
:
layout_centerHorizontal
=
"true"
android
:
layout_alignParentTop
=
"true"
/>
<DigitalClock
android
:
id
=
"@+id/digital"
android
:
layout_width
=
"wrap_content"
android
:
layout_height
=
"wrap_content"
android
:
layout_centerHorizontal
=
"true"
android
:
layout_below
=
"@id/analog"
/>
</RelativeLayout>
Puis les fichiers principaux de l'application :
Le fichier Layout principal de la classe MultiTabBrowserTuto qui déclare la structure usuelle d'une application à onglets :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
<?xml version="1.0" encoding="utf-8"?>
<TabHost
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
android
:
id
=
"@android:id/tabhost"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
>
<LinearLayout
android
:
orientation
=
"vertical"
android
:
layout_width
=
"fill_parent"
android
:
layout_height
=
"fill_parent"
android
:
padding
=
"5dp"
>
<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
:
padding
=
"5dp"
/>
</LinearLayout>
</TabHost>
Le fichier de ressource pour les icônes qui reroute automatiquement vers une ressource en fonction de son état « de sélection » :
2.
3.
4.
5.
6.
7.
8.
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
>
<!-- When selected, use grey -->
<item
android
:
drawable
=
"@drawable/ic_tab_grey"
android
:
state_selected
=
"true"
/>
<!-- When not selected, use white-->
<item
android
:
drawable
=
"@drawable/ic_tab_white"
/>
</selector>
Il est à noter que le dossier drawable contient deux icônes, ic_tab_grey.png et ic_tab_white.png qui sont dans les en-têtes des onglets et qui sont pointés par le fichier ci-dessus.
Et enfin le fichier manifest.xml de l'application. Trois choses sont importantes dans ce manifest.xml :
- Chaque activité est déclarée (il ne faut pas l'oublier).
- L'attribut noTitleBar est spécifié pour l'activité principale, ce qui permet de gagner un peu de place en hauteur.
- L'accès à Internet est demandé (nécessaire à l'activité WebKit).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns
:
android
=
"http://schemas.android.com/apk/res/android"
package
=
"net.stinfoservices.android.tuto.gui"
android
:
versionCode
=
"1"
android
:
versionName
=
"1.0"
>
<application
android
:
icon
=
"@drawable/icon"
android
:
label
=
"@string/app_name"
>
<activity
android
:
name
=
".MultiTabBrowserTuto"
android
:
label
=
"@string/app_name"
android
:
theme
=
"@android:style/Theme.NoTitleBar"
>
<intent-filter>
<action
android
:
name
=
"android.intent.action.MAIN"
/>
<category
android
:
name
=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<activity
android
:
name
=
"SiteWebSTI"
></activity>
<activity
android
:
name
=
"TextViewActivity"
></activity>
<activity
android
:
name
=
"ClockAD"
></activity>
</application>
<uses-sdk
android
:
minSdkVersion
=
"8"
/>
<uses-permission
android
:
name
=
"android.permission.INTERNET"
></uses-permission>
</manifest>
Voilà, une activité affichant un navigateur avec des onglets qui marchent avec les intentions. Ce qui correspond à l'état de l'art pour un programme Android qui se doit d'être un ensemble d'activités liées les unes aux autres au moyen d'intents.
I-F. Filtres d'intention standard▲
Vous trouverez dans http://developer.android.com/reference/android/content/Intent.html une très bonne description de ces intentions.
Les points suivants listent les paramètres les plus utilisés pour la déclaration d'intentions.
I-F-1. Action standard des activités▲
Actions courantes et standard que les Intents définissent pour lancer les activités (usuellement au moyen de startActivity(Intent)). Les plus importantes et les plus utilisées sont de loin ACTION_MAIN et ACTION_EDIT.
I-F-2. Actions standard d'un Broadcast▲
Actions courantes et standard que les Intents définissent pour recevoir les BroadCast (usuellement au moyen de registerReceiver(BroadcastReceiver, IntentFilter) ou au moyen du tag <receiver> dans le fichier manifest.xml).
- ACTION_TIME_TICK
- ACTION_TIME_CHANGED
- ACTION_TIMEZONE_CHANGED
- ACTION_BOOT_COMPLETED
- ACTION_PACKAGE_ADDED
- ACTION_PACKAGE_CHANGED
- ACTION_PACKAGE_REMOVED
- ACTION_PACKAGE_RESTARTED
- ACTION_PACKAGE_DATA_CLEARED
- ACTION_UID_REMOVED
- ACTION_BATTERY_CHANGED
- ACTION_POWER_CONNECTED
- ACTION_POWER_DISCONNECTED
- ACTION_SHUTDOWN
I-F-3. Catégories standard▲
Catégories courantes et standard qui peuvent être utilisées pour classifier les Intents au moyen de la méthode addCategory(String).
I-F-4. Extra Data standard▲
Champs courants et standard qui peuvent être utilisés comme données supplémentaires au moyen de la méthode putExtra(String, Bundle).
- EXTRA_ALARM_COUNT
- EXTRA_BCC
- EXTRA_CC
- EXTRA_CHANGED_COMPONENT_NAME
- EXTRA_DATA_REMOVED
- EXTRA_DOCK_STATE
- EXTRA_DOCK_STATE_CAR
- EXTRA_DOCK_STATE_DESK
- EXTRA_DOCK_STATE_UNDOCKED
- EXTRA_DONT_KILL_APP
- EXTRA_EMAIL
- EXTRA_INITIAL_INTENTS
- EXTRA_INTENT
- EXTRA_KEY_EVENT
- EXTRA_PHONE_NUMBER
- EXTRA_REMOTE_INTENT_TOKEN
- EXTRA_REPLACING
- EXTRA_SHORTCUT_ICON
- EXTRA_SHORTCUT_ICON_RESOURCE
- EXTRA_SHORTCUT_INTENT
- EXTRA_STREAM
- EXTRA_SHORTCUT_NAME
- EXTRA_SUBJECT
- EXTRA_TEMPLATE
- EXTRA_TEXT
- EXTRA_TITLE
- EXTRA_UID
II. La rotation▲
Lors de la rotation de l'écran, votre activité est détruite puis reconstruite.
Vous pouvez vous référer à la partie 5.2 : Gestion des événements du cycle de vie d'une activité.
Pour désactiver la rotation, il suffit de rajouter dans son fichier manifest.xml le type d'orientation (landscape, portrait ou sensor) de votre activité :
2.
3.
4.
5.
6.
7.
<activity
android
:
name
=
".LaunchDemo"
android
:
label
=
"LaunchDemo"
>
<intent-filter>
<action
android
:
name
=
"android.intent.action.MAIN"
android
:
screenOrientation
=
"landscape"
/>
<category
android
:
name
=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
Si vous mettez le paramètre sensor, cela demande à Android de faire pivoter l'activité en fonction de l'accéléromètre qui détecte quand l'écran est en mode portrait ou pas.
III. Remerciements▲
Cet article a été publié avec l'aimable autorisation de la société Android2EE.
Nous tenons à remercier Ced et f-leb pour la relecture orthographique de cet article et Mickael Baron pour la mise au format Developpez.com.