Cours Android

download Cours Android

of 75

Transcript of Cours Android

  • Dveloppement sous AndroidJean-Francois Lalande - November 2011Le but de ce cours est de dcouvrir la programmation sous Android, sa plate-forme de dveloppement etles spcificits du dveloppement embarqu sur tlphone mobile.Ce cours est bas sur l'excellent livre Programmation Android, de la conception au dploiement avec leSDK Google Android 2 [PA].

    Ce cours est mis disposition par Jean-Franois Lalande selon les termes de la licence CreativeCommons Attribution - Pas d'Utilisation Commerciale - Partage l'Identique 3.0 non transpos.

  • 1 Plan du module

    Plan du module1 Plan du module 22 Le SDK Android 33 Interfaces graphiques 94 Les Intents 195 Persistance des donnes 276 Les services, processus et threads 357 Connectivit 448 Divers 519 Annexes 5310 Bibliographie 75

    1 Plan du module Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 2 / 79

  • 2 Le SDK Android2.1 Android 3

    L'Operating System 3Projet ADT 4Les lments d'une application 4Le Manifest de l'application 4

    2.2 Les ressources 5

    Les chaines 5

    Autres valeurs simples 6Autres ressources 6

    2.3 Les activits 7Sauvegarde des interfaces d'activit 7Dmonstration 8

    2.1 AndroidL'ecosystme d'Android s'appuie sur deux piliers:

    le langage Java le SDK qui permet d'avoir un environnement de dveloppement facilitant la tche du dveloppeur

    Le kit de dveloppement donne accs des exemples, de la documentation mais surtout l'API deprogrammation du systme et un mulateur pour tester ses applications.Stratgiquement, Google utilise la licence Apache pour Android ce qui permet la redistribution du codesous forme libre ou non et d'en faire un usage commercial.Le plugin Android Development Tool permet d'intgrer les fonctionnalits du SDK Eclipse. Il fautl'installer comme un plugin classique en prcisant l'URL du plugin. Ensuite, il faut renseignerl'emplacement du SDK (pralablement tlcharg et dcompress) dans les prfrences du plugin ADT.

    L'Operating SystemAndroid est en fait un systme de la famille des Linux, pour une fois sans les outils GNU. L'OS s'appuiesur:

    un noyau Linux (et ses drivers) une machine virtuelle: Dalvik Virtual Machine

    des applications (navigateur, gestion contact, application de tlphonie...) des bibliothques (SSL, SQLite, OpenGL ES, etc...)

    [Dalvik] est le nom de la machine virtuelle open-source utilise sur les systmes Android. Cette machinevirtuelle excute des fichiers .dex, plus ramasss que les .class classiques. Ce format vite par exemplela duplication des String constantes. La machine virtuelle utilise elle-mme moins d'espace mmoire etl'adressage des constantes se fait par un pointeur de 32 bits.

    2 Le SDK Android Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 3 / 79

  • [Dalvik] n'est pas compatible avec une JVM du type Java SE ou mme Java ME. La librairie d'accs estdonc redfinie entirement par Google.

    Projet ADTUn projet bas sur le plugin ADT est dcompos de la manire suivante:

    src/: les sources Java du projet libs/: bibliothques tierces res/:

    res/drawable: ressources images res/layout: description des IHMs en XML res/values: chaines de caractres et dimensions

    gen/: les ressources auto gnres par ADT assets/: ressources brutes (raw bytes) bin/:

    bin/classes: les classes compiles en .class bin/classes.dex: excutable pour la JVM Dalvik bin/myapp.zip: les ressources de l'application bin/myapp.apk: application empaquete avec ses ressource et prte pour le dploiement

    Les lments d'une applicationUne application Android est compose des lments suivants:

    des activits (android.app.Activity): il s'agit d'une partie de l'application prsentant une vue l'utilisateur

    des services (android.app.Service): il s'agit d'une activit tche de fondsans vue associe des fournisseurs de contenus (android.content.ContentProvider): permet le partage d'informations

    au sein ou entre applications des widgets (android.appwidget.*): une vue accroche au Bureau d'Android des Intents (android.content.Intent): permet d'envoyer un message pour un composant externe

    sans le nommer explicitement des rcepteurs d'Intents (android.content.BroadcastReceiver): permet de dclarer tre capable de

    rpondre des Intents des notifications (android.app.Notifications): permet de notifier l'utilisateur de la survenue

    d'vnements

    Le Manifest de l'applicationLe fichier AndroidManifest.xml dclare l'ensemble des lments de l'application.

  • android:versionCode="1" android:versionName="1.0">

    ... ... ...

    2.2 Les ressourcesLes ressources de l'applications sont utilises dans le code au travers de la classe statique R. ADTre-gnre automatiquement la classe statique R chaque changement dans le projet. Toutes lesressources sont accessibles au travers de R, ds qu'elles sont dclares dans le fichier XML ou que lefichier associ est dpos dans le rpertoire adquat. Les ressources sont utilises de la maniresuivante:

    android.R.type_ressource.nom_ressource

    qui est de type int. Il s'agit en fait de l'identifiant de la ressource. On peut alors utiliser cet identifiant ourcuprer l'instance de la ressource en utilisant la classe Resources:

    Resources res = getResources();String hw = res.getString(R.string.hello);XXX o = res.getXXX(id);

    Une mthode spcifique pour les objets graphiques permet de les rcuprer partir de leur id, ce quipermet d'agir sur ces instances mme si elles ont t cres via leur dfinition XML:

    TextView texte = (TextView)findViewById(R.id.le_texte);texte.setText("Here we go !");

    Les chainesLes chaines constantes de l'application sont situes dans res/values/strings.xml. L'externalisation deschaines permettra de raliser l'internationalisation de l'application. Voici un exemple:

    2.2 Les ressources Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 5 / 79

  • Hello Hello JFL ! AndroJF

    Resources res = getResources();String hw = res.getString(R.string.hello);

    Autres valeurs simplesPlusieurs fichies xml peuvent tre placs dans res/values. Cela permet de dfinit des chaines, descouleurs, des tableaux. L'assistant de cration permet de crer de nouveaux fichiers de ressourcescontenant des valeurs simples, comme par exemple un tableau de chaines:

    it1 it2

    Autres ressourcesD'autres ressources sont spcifiables dans res:

    les menus

    Autres valeurs simples Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 6 / 79

  • les images (R.drawable) des dimensions (R.dimen) des couleurs (R.color)

    2.3 Les activitsUne application Android tant heberge sur un systme embarqu, le cycle de vie d'une applicationressemble celle d'une application Java ME. L'activit peut passer des tats:

    dmarrage -> actif: dtient le focus et est dmarr (onStart invoqu) actif -> suspendue: ne dtient plus le focus (onPause invoqu) suspendue -> actif: onResume invoqu suspendue -> dtruit: onDestroy invoqu

    public class Main extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acceuil); } protected void onDestroy() { super.onDestroy(); } protected void onPause() { super.onPause(); } protected void onResume() { super.onResume(); } protected void onStart() { super.onStart(); } protected void onStop() { super.onStop(); } }

    Sauvegarde des interfaces d'activitL'objet Bundle pass en paramtre de la mthode onCreate permet de restaurer les valeurs desinterfaces d'une activit qui a t dcharge de la mmoire. En effet, lorsque l'on appuie par exemple surla touche Home, en revenant sur le bureau, Android peut-tre amen dcharg les lments graphiquesde la mmoire pour gagner des ressources. Si l'on rebascule sur l'application (appui long sur Home),l'application peut avoir perdu les valeurs saisis dans les zones de texte.Pour forcer Android dcharger les valeurs, il est possible d'aller dans "Development tools >Development Settings" et de cocher "Immediately destroy activities".Si une zone de texte n'a pas d'identifiant, Android ne pourra pas la sauver et elle ne pourra pas trerestaure partir de l'objet Bundle.Si l'application est compltement dtruite (tue), rien n'est restaur.Le code suivant permet de visualiser le dclenchement des sauvegardes:

    protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); Toast.makeText(this, "Sauvegarde !", Toast.LENGTH_LONG).show();}

    2.3 Les activits Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 7 / 79

  • Dmonstration

    Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 8 / 79

  • 3 Interfaces graphiques3.1 Vues et gabarits 9

    Attributs des gabarits 9L'interface comme ressource 10

    3.2 Les lments graphiques de base 10Les labels de texte 11Les zones de texte 11Les images 12Les boutons 12Interface rsultat 12Dmonstration 13

    3.3 Positionnement avanc 13Preview du positionnement 13

    3.4 Les listes 14Dmonstration 14Liste de layouts plus complexes 14Interface rsultat 15

    3.5 Les onglets 16Activit et onglets 17Crer les onglets 17Dmonstration 18

    3.1 Vues et gabaritsLes lements graphiques hritent de la classe View. On peut regrouper des lments graphiques dansune ViewGroup. Des ViewGroup particuliers sont prdfinis: ce sont des gabarits (layout) qui proposentune prdispositions des objets graphiques:

    LinearLayout: dispose les lments de gauche droite ou du haut vers le bas RelativeLayout: les lments enfants les uns par rapport aux autres TableLayout: disposition matricielle FrameLayout: disposition en haut gauche en empilant les lments

    Les dclarations se font principalement en XML, ce qui vite de passer par les instanciations Java.

    Attributs des gabaritsLes attributs des gabarits permettent de spcifier des attributs supplmentaires. Les plus importants sont:

    android:layout_width et android:layout_height:

    ="fill_parent": l'lment remplit tout l'lment parent

    3 Interfaces graphiques Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 9 / 79

  • ="wrap_content": prend la place ncessaire l'affichage android:orientation: dfinit l'orientation d'empilement android:gravity: dfinit l'alignement des lments

    Voici un exemple de LinearLayout:

    L'interface comme ressourceUne interface graphique dfinie en XML sera aussi gnre comme une ressource dans la classe statiqueR. Le nom du fichier xml, par example accueil.xml permet de retrouver le layout dans le code java autravers de R.layout.accueil.Ainsi, pour associer la premire vue graphique l'activit principale de l'application, il faut faire:

    public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.acceuil);}

    Le layout reste modifiable au travers du code, comme tous les autres objets graphiques. Pour cela, il estimportant de spcifier un id dans la dfinition XML du gabarit (android:id="@+id/accueilid"). Cetteremarque est aussi valable pour tous les autres objets graphiques. Ainsi, on peut accder cet lmentpar son id et agir dessus au travers du code Java:

    LinearLayout l = (LinearLayout)findViewById(R.id.accueilid);l.setBackgroundColor(Color.BLACK);

    3.2 Les lments graphiques de baseUn gabarit peut contenir des lments graphiques, ou d'autres gabarits. On retrouve le mme principeque les tableaux imbriqus de l'HTML.Les interfaces peuvent aussi inclure d'autres interfaces, permettant de factoriser des morceauxd'interface. On utilise dans ce cas le mot clef include:

  • android:layout_width="wrap_content" android:layout_height="wrap_content" layout="@layout/acceuil" >

    Les labels de texteEn XML:

    Par la programmation:

    public class Activity2 extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout gabarit = new LinearLayout(this); gabarit.setGravity(Gravity.CENTER); // centrer les lments graphiques gabarit.setOrientation(LinearLayout.VERTICAL); // empiler vers le bas !

    TextView texte = new TextView(this); texte.setText("Programming creation of interface !"); gabarit.addView(texte); setContentView(gabarit);} }

    Les zones de texteEn XML:

    Par la programmation:

    EditText edit = new EditText(this);edit.setText("Edit me");gabarit.addView(edit);

    Interception d'vnements:

    Les labels de texte Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 11 / 79

  • edit.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // do something here });

    Les imagesEn XML:

    Par la programmation:

    ImageView image = new ImageView(this);image.setImageResource(R.drawable.ensi);gabarit.addView(image);

    Les boutonsEn XML:

    La gestion des vnements de click se font par l'intermdiaire d'un listener:

    Button b = (Button)findViewById(R.id.Button01);b.setOnClickListener(new OnClickListener() {

    @Override public void onClick(View v) { Toast.makeText(v.getContext(), "Stop !", Toast.LENGTH_LONG).show(); } });}

    Interface rsultat

    Les images Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 12 / 79

  • Ce screenshot montre une interface contenant des TextView, EditText, ImageView, et un bouton (cf.ANX_Interfaces-graphiques).

    Dmonstration

    3.3 Positionnement avancPour obtenir une interface agrable, il est souvent ncessaire de raliser correctement le positionnementdes lments graphiques. La difficult est d'arriver programmer un placement qui n'est pas dpendantde l'orientation ou de la taille de l'cran.Dans [VL], on trouve une explication pour raliser un placement simple: un texte gauche et une image droite de l'cran, aligne avec le texte. Cela peut tre particulirement utile si par exemple on ralise uneliste d'item qui contienne chaque fois un texte et une icone.Le principe rside dans l'imbrication de LinearLayout:

    Un premier layout contiendra l'ensemble des lments. Son orientation doit tre horizontal et sagravit (gravity) center. On inclut ensuite le texte.

    Puis, l'image tant cense tre droite, il faut crer un LinearLayout conscutif au texte et prciserque la gravit (gravity) est right. Pour aligner les lments, il faut prciser que la gravit du layout(layout_gravity) est center.

    Preview du positionnementLe layout dcrit ci-avant ressemble :

  • android:orientation="horizontal" android:layout_width="fill_parent" android:gravity="right" android:layout_gravity="center">

    Ce qui produit dans l'interface de preview, en orientation portrait:

    3.4 Les listesAu sein d'un gabarit, on peut implanter une liste que l'on pourra drouler si le nombre d'lments estimportant. Si l'on souhaite faire une liste plein cran, il suffit juste de poser un layout linaire et d'yimplanter une ListView. Le XML du gabarit est donc:

    Etant donn qu'une liste peut contenir des lments graphiques divers et varis, les lments de la listedoivent tre insrs dans un ListAdapter et il faut aussi dfinir le gabarit qui sera utilis pour afficherchaque lment du ListAdapter. Prenons un exemple simple: une liste de chaine de caractres. Dans cecas, on cr un nouveau gabarit montexte et on ajoute dynamiquement un ArrayAdapter la listelistView1. Le gabarit suivant doit tre plac dans montexte.xml:

    Le code de l'application qui cr la liste peut tre:

    ListView list = (ListView)findViewById(R.id.listView1);ArrayAdapter tableau = new ArrayAdapter(list.getContext(), R.layout.montexte);for (int i=0; i

  • Lorsque les listes contiennent un layout plus complexe qu'un texte, il faut utiliser un autre constructeur deArrayAdapter (ci-dessous) o resource est l'id du layout appliquer chaque ligne ettextViewResourceId est l'id de la zone de texte inclu dans ce layout complexe. A chaque entre de laliste, la vue gnre utilisera le layout complexe et la zone de texte contiendra la string passe enargument la mthode add.

    ArrayAdapter (Context context, int resource, int textViewResourceId)

    Le code de l'exemple prcdent doit tre adapt comme ceci:

    ListView list = (ListView)findViewById(R.id.maliste);ArrayAdapter tableau = new ArrayAdapter( list.getContext(), R.layout.ligne, R.id.monTexte);for (int i=0; i

  • 3.5 Les ongletsLa ralisation d'onglets permet de mieux utiliser l'espace rduit de l'cran. Pour raliser les onglets, il fautsuivre une structure trs particulire pour le gabarit. Les diffrents onglets sont ensuite crdynamiquement par le code, en associant chaque onglet l'activit correspondante.La dfinition du gabarit doit tre la suivante:

    Certains ids sont imposs lorsqu'on utilise des onglets:

    TabHost : android:id= "@android:id/tabhost" TabWidget : android:id= "@android:id/tabs" FrameLayout : android:id= "@android:id/tabcontent"

    3.5 Les onglets Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 16 / 79

  • Activit et ongletsL'activit qui gre l'ensemble des onglets est une activit spciale hritant de TabActivity. Le gabaritprcdents est donc associ une classe dfinir hritant de TabActivity:

    public class AndroTabs2Activity extends TabActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ...

    Chaque onglet contient, dans sa partie du bas, une activit qu'il convient de crer. Pour chaque activit, ilfaut donc dfinir une classe d'activit et lui associer son gabarit:

    public class ActivityOnglet1 extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.onglet1);}}

    Crer les ongletsEnsuite, dans l'activit principale hritant de TabActivity, il faut crer dynamiquement les onglets et lesremplir:

    TabHost tabHost = getTabHost();TabHost.TabSpec spec;Intent intent;

    // Cration de l'intent lancant l'activit de l'ongletintent = new Intent().setClass(this, ActivityOnglet1.class);// Cration dynamique d'une configuration pour l'onglet 1spec = tabHost.newTabSpec("Onglet 1");spec.setContent(intent); // Associer l'intent l'ongletspec.setIndicator("Onglet 1"); // Ajouter un texte dans l'onglettabHost.addTab(spec); // Ajout de l'onglet

    ...

    // Choisir l'onglet par dfauttabHost.setCurrentTab(0);

    Sans oublier de dclarer les activits dans le Manifest:

    Activit et onglets Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 17 / 79

  • Dmonstration(cf ANX_Onglets)

    Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 18 / 79

  • 4 Les Intents4.1 Principe des Intents 194.2 Utilisation d'Intents 19

    Retour d'une activit 20Rsultat d'une activit 20Principe de la Dmonstration 21Dmonstration 21

    4.3 Grer les actions 21Contrler les actions permises 22Exemples de permissions 22Echec de permissions 23Dmonstration 23Broadcaster des Intents informatifs 23

    4.4 Recevoir et filtrer les Intents 24Filtrage d'un Intent par l'activit 24Rception par un BroadcastReceiver 24Rcepteur d'Intent dynamique 25Les messages natifs 25Principe de la Dmonstration 26Dmonstration 26

    4.1 Principe des IntentsLes Intents permettent de grer l'envoi et la rception de messages afin de faire cooprer les applications.Le but des Intents est de dlguer une action un autre composant, une autre application ou une autreactivit de l'application courante.Un objet Intent contient les information suivantes:

    le nom du composant cibl (facultatif) l'action raliser, sous forme de chaine de caractres les donnes: contenu MIME et URI des donnes supplmentaires sous forme de paires de clef/valeur une catgorie pour cibler un type d'application des drapeaux (information supplmentaire)

    4.2 Utilisation d'IntentsIl y a plusieurs faons d'appeler un Intent:

    4 Les Intents Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 19 / 79

  • on cre l'objet et on passe la classe de l'activit cible par l'Intent: cela revient passer la main une autre activit de l'application.

    Intent login = new Intent(this, GiveLogin.class);startActivity(login);

    on cre l'objet et on lui donne les donnes et l'URI cible: l'OS est charg de trouver une applicationpouvant rpondre l'Intent.

    Button b = (Button)findViewById(R.id.Button01);b.setOnClickListener(new OnClickListener() {

    @Overridepublic void onClick(View v) { Uri telnumber = Uri.parse("tel:0248484000"); Intent call = new Intent(Intent.ACTION_DIAL, telnumber); startActivity(call);}});

    Sans oublier de dclarer la nouvelle activit dans le Manifest.

    Retour d'une activitLorsque le bouton retour est press, l'activit courante prend fin et revient l'activit prcdente. Celapermet par exemple de terminer son appel tlphonique et de revenir l'interface ayant initi l'appel.Au sein d'une application, une activit peut vouloir rcuprer un code de retour de l'activit "enfant". Onutilise pour cela la mthode startActivityForResult qui envoie un code de retour l'activit enfant.Lorsque l'activit parent reprend la main, il devient possible de filtrer le code de retour dans la mthodeonActivityResult pour savoir si l'on revient ou pas de l'activit enfant.L'appel d'un Ident devient donc:

    public void onCreate(Bundle savedInstanceState) { Intent login = new Intent(getApplicationContext(), GivePhoneNumber.class); startActivityForResult(login,48);... }

    Le filtrage dans la classe parente permet de savoir qui avait appel cette activit enfant:

    protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == 48) Toast.makeText(this, "Code de requte rcupr (je sais d'ou je viens)", Toast.LENGTH_LONG).show();}

    Rsultat d'une activitIl est aussi possible de dfinir un rsultat d'activit, avant d'appeler explicitement la fin d'une activit avec la mthode finish(). Dans ce cas, la mthode setResult permet d'enregistrer un code de retour qu'il sera

    Retour d'une activit Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 20 / 79

  • aussi possible de filtrer dans l'activit parente.Dans l'activit enfant, on met donc:

    Button finish = (Button)findViewById(R.id.finish); finish.setOnClickListener(new OnClickListener() {

    @Override public void onClick(View v) { setResult(50); finish(); }});

    Et la classe parente peut filtrer ainsi:

    protected void onActivityResult(int requestCode, int resultCode, Intent data){ if (requestCode == 48) Toast.makeText(this, "Code de requte rcupr (je sais d'ou je viens)", Toast.LENGTH_LONG).show(); if (resultCode == 50) Toast.makeText(this, "Code de retour ok (on m'a renvoy le bon code)", Toast.LENGTH_LONG).show();}

    Principe de la Dmonstration(cf ANX_Intents)

    Dmonstration

    4.3 Grer les actions

    Principe de la Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 21 / 79

  • Plusieurs actions natives existent par dfaut sur Android. La plus courante est l'actionIntent.ACTION_VIEW qui permet d'appeler une application pour visualiser un contenu dont on donnel'URI. Les autres actions sont:

    ACTION_CALL (ANSWER, DIAL): passer/rceptionner/afficher un appel ACTION_EDIT (DELETE): diter/supprimer une donne ACTION_SEND: envoyer des donnes par SMS ou E-mail ACTION_WEB_SEARCH: rechercher sur internet

    Voici un exemple d'envoi d'[E-mail]:

    Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);String[] recipients = new String[]{"[email protected]", "",};emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, recipients);emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Test");emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, "Message");emailIntent.setType("text/plain");startActivity(Intent.createChooser(emailIntent, "Send mail..."));finish();

    Contrler les actions permisesAndroid propose un systme de permissions, permettant au dveloppeur de dclarer les permissionsrequises par son application. L'utilisateur peut ainsi savoir, au moment de l'installation, les permissionsdemandes par l'application, ce qui est particulirement utile pour une application dans laquellel'utilisateur n'a pas totalement confiance.Pour dclarer une permission, il suffit de le prciser dans le Manifest:

    Attention, si vous n'avez pas prcis la cration de projet de numro de version minimum, lespermissions READ_PHONE_STATE et WRITE_EXTERNAL_STORAGE sont accordes par dfaut [SO].Pour avoir le nombre minimal de permissions, il faut ajouter au Manifest:

    La liste compltes des permissions permet de contrler finement les droits allous l'application.Attention ne pas confondre permissions et dlgation: ne pas donner la permission de passer un appeln'empche pas l'application de dlguer, via un Intent, le passage d'un appel. Par contre, un appel directdepuis l'application n'est pas possible.

    Exemples de permissionsCes exemples montrent deux applications n'ayant pas les mmes permissions:

    Contrler les actions permises Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 22 / 79

  • Echec de permissionsSans aucun test utilisateur, ne pas donner une permission provoque la leve d'une exception dansl'application, comme pour la permission CALL_PHONE dans cet exemple:

    Dmonstration

    Broadcaster des Intents informatifsIl est aussi possible d'utiliser un objet Intent pour broadcaster un message but informatif. Ainsi, toutesles applications pourront capturer ce message et rcuprer l'information.

    Intent broadcast = new Intent("andro.jf.broadcast");broadcast.putExtra("extra", "test");sendBroadcast(broadcast);

    Echec de permissions Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 23 / 79

  • La mthode putExtra permet d'enregistrer un paire clef/valeur dans l'Intent. On peut rcuprer lesdonnes l'aide de la mthode getExtras dans l'objet Bundle qui est dans l'Intent:

    Bundle extra = intent.getExtras();String val = extra.getString("extra");

    4.4 Recevoir et filtrer les IntentsEtant donn la multitude de message d'Intent, chaque application doit pouvoir facilement "couter" lesIntents dont elle a besoin. Android dispose d'un systme de filtres dclaratifs permettant de dfinir dans leManifest des filtres.Un filtre peut utiliser plusieurs niveaux de filtrage:

    action: identifie le nom de l'Intent. Pour viter les collisions, il faut utiliser la convention de nommagede Java

    category: permet de filtrer une catgorie d'action (DEFAULT, BROWSABLE, ...) data: filtre sur les donnes du message par exemple en utilisant android:host pour filtrer un nom de

    domaine particulier

    Filtrage d'un Intent par l'activitEn dclarant un filtre au niveau du tag activity, l'application dclare les types de messsage qu'elle saitgrer.

    Ainsi, l'application rpond la sollicitation des Intents envoys par:

    Button autoinvoc = (Button)findViewById(R.id.autoinvoc);autoinvoc.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) { Intent broadcast = new Intent("andro.jf.nom_du_message"); broadcast.putExtra("extra", "test"); startActivity(broadcast);}});

    L'application est relance (ou lance). Elle peut rcuprer les donnes de l'Intent dans son main:

    String data = getIntent().getDataString();Uri uri = getIntent().getData();

    Rception par un BroadcastReceiver

    4.4 Recevoir et filtrer les Intents Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 24 / 79

  • Les messages broadcasts par les applications sont rceptionnes par une classe hritant deBroadcastReceiver. Cette classe doit surcharger la mthode onReceive. Dans le Manifest, un filtre doittre insr dans un tag receiver qui pointe vers la classe se chargeant des messages.Dans le Manifest:

    La classe hritant de BroadcastReceiver:

    public final class MyBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle extra = intent.getExtras(); if (extra != null) { String val = extra.getString("extra"); Toast.makeText(context, "Broadcast message received: " + val, Toast.LENGTH_SHORT).show();}}}

    Rcepteur d'Intent dynamiqueIl est possible de crer un rcepteur et d'installer le filtre correspondant dynamiquement.

    private MyBroadcastReceiverDyn myreceiver;

    public void onCreate(Bundle savedInstanceState) { // Broadcast receiver dynamique myreceiver = new MyBroadcastReceiverDyn(); IntentFilter filtre = new IntentFilter("andro.jf.broadcast"); registerReceiver(myreceiver, filtre);}

    Lorsque ce receiver n'est plus utile, il faut le dsenregistrer pour ainsi librer les ressources:

    unregisterReceiver(myreceiver);

    C'est particulirement important puisque un filtre de rception reste actif mme si l'application est teinte(elle peut tre relance si un message la concernant survient).

    Les messages natifsUn certain nombre de messages sont diffuss par l'OS:

    Rcepteur d'Intent dynamique Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 25 / 79

  • ACTION_BOOT_COMPLETED: diffus lorsque le systme a fini son boot ACTION_SHUTDOWN: diffus lorsque le systme est en cours d'extinction ACTION_SCREEN_ON / OFF: allumage / exctinction de l'cran ACTION_POWER_CONNECTED / DISCONNECTED: connexion / perte de l'alimentation ACTION_TIME_TICK: une notification envoye toutes les minutes ACTION_USER_PRESENT: notification recue lorsque l'utilisateur dlock son tlphone ...

    Tous les messages de broadcast se trouvent dans la documentation des Intents.

    Principe de la Dmonstration

    Dmonstration(cf ANX_Receveur-de-broadcasts)

    Principe de la Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 26 / 79

  • 5 Persistance des donnes5.1 Diffrentes persistances 275.2 Prfrences partages 27

    Reprsentation XML d'un menu de prfrences 28Activit d'dition de prfrences 28Attributs des prfrences 29Prfrences: toggle et texte 29Prfrences: listes 30Ecriture de prfrences 30Dmonstration 31

    5.3 Les fichiers 315.4 BDD SQLite 31

    Lecture / Ecriture dans la BDD 325.5 XML 32

    SAX parser 33DOM parser 33

    5.1 Diffrentes persistancesAndroid fournit plusieurs mthodes pour faire persister les donnes applicatives:

    la persistance des donnes de l'activit (cf Le SDK Android) un mcanisme de sauvegarde cl/valeur, utilis pour les fichiers de prfrences (appel prfrences

    partages) des entres sorties de type fichier une base de donne bas sur SQLite

    La persistance des donnes des activits est gr par l'objet Bundle qui permet de restaurer les View quipossde un id. S'il est ncessaire de raliser une sauvegarde plus personnalise, il suffit de recoder lesmthodes onSaveInstanceState et onCreate et d'utiliser les mthodes qui permettent de lire/crire desdonnes sur l'objet Bundle.Android fournit aussi automatiquement, la persistance du chemin de navigation de l'utilisateur, ce qui lerenvoie la bonne activit lorsqu'il appuie sur la touche Retour.

    5.2 Prfrences partagesLa classe SharedPreferences permet de grer des paires de cl/valeurs associes une activit. Onrcupre un tel objet par l'appel getPreferences:

    SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);String nom = prefs.getString("login", null);Long nom = prefs.getLong("taille", null);

    5 Persistance des donnes Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 27 / 79

  • La mthode getPreferences(int) appelle en fait getPreferences(String, int) partir du nom de la classede l'activit courante. Le mode MODE_PRIVATE restreint l'accs au fichier cr l'application. Lesmodes d'accs MODE_WORLD_READABLE et MODE_WORLD_WRITABLE permettent aux autresapplications de lire/crire ce fichier.L'intrt d'utiliser le systme de prfrences prvu par Android rside dans le fait que l'interface graphiqueassoci la modification des prfrences est dj programm: pas besoin de crer l'interface de l'activitpour cela. L'interface sera gnre automatiquement par Android et peut ressembler par exemple cela:

    Reprsentation XML d'un menu de prfrencesUne activit spcifique a t programme pour raliser un cran d'dition de prfrences. Il s'agit dePreferenceActivity. A partir d'une description XML des prfrences, la classe permet d'afficher un crancompos de modificateurs pour chaque type de prfrences dclares.Voici un exemple de dclarations de prfrences XML, stocker dans res/xml/preferences.xml:

    ... other preferences here ...

    Activit d'dition de prfrencesPour afficher l'cran d'dition des prfrences correspondant sa description XML, il faut crer unenouvelle activit qui hrite de PreferenceActivity et simplement appeler la mthodeaddPreferencesFromResource en donnant l'id de la description XML:

    public class MyPrefs extends PreferenceActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences);}}

    Pour lancer cette activit, on cre un bouton et un Intent correspondant.

    Reprsentation XML d'un menu de prfrences Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 28 / 79

  • Attributs des prfrencesLes attributs suivants sont utiles:

    android:title: La string apparaissant comme nom de la prfrence android:summary: Une phrase permettant d'expliciter la prfrence android:key: La clef pour l'enregistrement de la prfrence

    Pour accder aux valeurs des prfrences, on utiliser la mthode getDefaultSharedPreferences sur laclasse PreferenceManager. On revient alors la lecture des prfrences comme pour celles qui sontassocies une activit. C'est la clef spcifie par l'attribut android:key qui est utilise pour rcuprer lavaleur choisie par l'utilisateur.

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());String login = prefs.getString("login","");

    Des attributs spcifiques certains types de prfrences peuvent tre utiliss, par exempleandroid:summaryOn pour les cases cocher qui donne la chaine afficher lorsque la prfrence estcoche.On peut faire dpendre une prfrence d'une autre, l'aide de l'attribut android:dependency. Parexemple, on peut spcifier dans cet attribut le nom de la clef d'une prfrence de type case cocher:

    Prfrences: toggle et texteUne case cocher se fait l'aide de CheckBoxPreference

    Un champs texte est saisi via EditTextPreference:

    Attributs des prfrences Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 29 / 79

  • Prfrences: listesUne entre de prfrence peut tre lie une liste de paires de clef-valeur dans les ressources:

    "Petite" "Moyenne" "Grande" "1" "5" "20"

    qui se dclare dans le menu de prfrences:

    Lorsque l'on choisit la prfrence "Petite", la prfrence vitesse est associe "1".

    Ecriture de prfrencesIl est aussi possible d'craser des prfrences par le code, par exemple si une action fait changer leparamtrage de l'application ou si l'on recoit le paramtrage par le rseau.L'criture de prfrences est plus complexe: elle passe au travers d'un diteur qui doit raliser un commitdes modifications (commit atomique, pour viter un mix entre plusieurs critures simultanes):

    SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);Editor editor = prefs.edit();editor.putString("login", "jf");editor.commit();

    Prfrences: listes Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 30 / 79

  • Il est mme possible de ragir un changement de prfrences en installant un couteur sur celles-ci:

    prefs.registerOnSharedPreferenceChangeListener( new OnSharedPreferenceChanged () { ...

    });

    Dmonstration(cf ANX_Gestion-des-prfrences)

    5.3 Les fichiersAndroid fournit aussi un accs classique au systme de fichier pour tous les cas qui ne sont pas couvertspar les prfrences ou la persistance des activits, c'est dire de nombreux cas. Le choix de Google estde s'appuyer sur les classes classiques de Java EE tout en simplifiant la gestion des permissions et desfichiers embarqus dans l'application.Pour la gestion des permissions, on retrouve comme pour les prfrences les constantesMODE__PRIVATE et MODE_WORLD_READABLE/WRITABLE passer en paramtre de l'ouverture dufichier. En utilisant ces constantes comme un masque, on peut ajouter | MODE_APPEND pour ajouterdes donnes.

    try { FileOutputStream out = openFileOutputStream("fichier", MODE_PRIVATE); ...

    } catch (FileNotFoundException e) { ... }

    Les ressources permettent aussi de rcuprer un fichier embarqu dans l'application:

    Resources res = getResources();InputStream is = res.openRawResource(R.raw.fichier);

    A noter: les fichier sont viter. Mieux vaut allger l'application au maximum et prvoir le tlchargementde ressources ncessaires et l'utilisation de fournisseurs de contenu.

    5.4 BDD SQLiteAndroid dispose d'une base de donne relationelle base sur SQLite. Mme si la base doit tre utiliseavec parcimonie, cela fournit un moyen efficace de grer une petite quantit de donne.[DBSQL] prsente un exemple de cration de base de donnes, ce qui se fait en hritant deSQLiteOpenHelper:

    public class DictionaryOpenHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 2; private static final String DICTIONARY_TABLE_NAME = "dictionary"; private static final String DICTIONARY_TABLE_CREATE = "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" + KEY_WORD + " TEXT, " + KEY_DEFINITION + " TEXT);";

    Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 31 / 79

  • DictionaryOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); }

    @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DICTIONARY_TABLE_CREATE); }}

    Lecture / Ecriture dans la BDDPour raliser des critures ou lectures, on utilise les mthodes getWritableDatabase() etgetReadableDatabase() qui renvoient une instance de SQLiteDatabase. Sur cet objet, une requte peuttre excute au travers de la mthode query():

    public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)

    L'objet de type Cursor permet de traiter la rponse (en lecture ou criture), par exemple: getCount(): nombre de lignes de la rponse moveToFirst(): dplace le curseur de rponse la premire ligne getInt(int columnIndex): retourne la valeur (int) de la colonne passe en paramtre getString(int columnIndex): retourne la valeur (String) de la colonne passe en paramtre moveToNext(): avance la ligne suivante getColumnName(int): donne le nom de la colonne dsigne par l'index ...

    5.5 XML[XML] Sans surprise, Android fournit plusieurs parsers XML (Pull parser, Document parser, Push parser).SAX et DOM sont disponibles. L'API de streaming (StAX) n'est pas disponible (mais pourrait le devenir).Cependant, une librairie quivalente est disponible: XmlPullParser. Voici un exemple simple:

    String s = new String("Coucou !");InputStream f = new ByteArrayInputStream(s.getBytes());XmlPullParser parser = Xml.newPullParser();try { // auto-detect the encoding from the stream parser.setInput(f, null);

    parser.next(); Toast.makeText(this, parser.getName(), Toast.LENGTH_LONG).show(); parser.next(); Toast.makeText(this, parser.getName(), Toast.LENGTH_LONG).show();

    Lecture / Ecriture dans la BDD Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 32 / 79

  • Toast.makeText(this, parser.getAttributeValue(null, "attr"), Toast.LENGTH_LONG).show(); parser.nextText(); Toast.makeText(this, parser.getText(), Toast.LENGTH_LONG).show();} ...

    SAX parserSAX s'utilise trs classiquement, comme en Java SE. Voici un exemple attaquant du XML au traversd'une connexion http:

    URI u = new URI("https://www.site.com/api/xml/list?apikey=845ef");DefaultHttpClient httpclient = new DefaultHttpClient();HttpGet httpget = new HttpGet(u);HttpResponse response = httpclient.execute(httpget);HttpEntity entity = response.getEntity();InputStream stream = entity.getContent();InputSource source = new InputSource(stream);

    SAXParserFactory spf = SAXParserFactory.newInstance();SAXParser sp = spf.newSAXParser();XMLReader xr = sp.getXMLReader();DefaultHandler handler = new DefaultHandler() { @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {

    Vector monitors = new Vector();

    if (localName.equals("monitor")) { monitors.add(attributes.getValue("displayname")); }}};xr.setContentHandler(handler);xr.parse(source);

    DOM parserEnfin, le paser DOM permet de naviguer assez facilement dans la reprsentation arborescente dudocument XML. L'exemple suivant permet de chercher tous les tags "monitor" dans les sous-tags de laracine.

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();try { DocumentBuilder builder = factory.newDocumentBuilder(); Document dom = builder.parse(source); Element root = dom.getDocumentElement(); // Rcupre tous les tags du descendant de la racine s'appelant monitor NodeList items = root.getElementsByTagName("monitor"); for (int i=0;i

  • // Traitement: // item.getNodeName() // item.getTextContent() // item.getAttributes() ...

    } } catch (...)

    SAX parser Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 34 / 79

  • 6 Les services, processus et threadsLa structure d'une classe de service ressemble une activit. Pour raliser un service, on hrite de laclasse Service et on implmente les mthodes de cration/dmarrage/arrt du service. La nouvellemthode qu'il faut implmenter ici est onBind qui permet aux IPC de faire des appels des mthodesdistantes.

    public class MyService extends Service { public void onCreate() { // Cration du service } public void onDestroy() { // Destruction du service } @deprecated // utile pour les versions antrieures d'Android 2.0 public void onStart(Intent intent, int startId) { // Dmarrage du service } public int onStartCommand(Intent intent, int flags, int startId) { // Dmarrage du service return START_STICKY; } public IBinder onBind(Intent arg0) { return null;}}

    Le service se dclare dans le Manifest dans le tag application:

    6.1 Dmarrer / Arrter un serviceLes Intents fournissent un moyen de dmarrer/arrter un service en utilisant le nom de la classe duservice ou un identifiant d'action:

    startService(new Intent(this, AndroService.class));stopService(new Intent(this, AndroService.class));startService(new Intent("andro.jf.manageServiceAction"));

    Ces mthodes sont invoquer dans l'activit de l'application dveloppe. On dit alors que le service estlocal l'application: il va mme s'excuter dans le thread de l'application. Un bouton de dmarrage d'unservice local est simple coder:

    Button b = (Button) findViewById(R.id.button1);b.setOnClickListener(new OnClickListener() {

    public void onClick(View v) { Intent startService = new Intent("andro.jf.manageServiceAction"); startService(startService); }

    6 Les services, processus et threads Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 35 / 79

  • });

    Auto dmarrage d'un serviceIl est aussi possible de faire dmarrer un service au dmarrage du systme. Pour cela, il faut crer unBroadcastReceiver qui va ragir l'action BOOT_COMPLETED et lancer l'Intent au travers de lamthode startService.Le Manifest contient donc:

    Et la classe AutoStart doit tre:

    public class AutoStart extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Intent startServiceIntent = new Intent(context, AndroService.class); context.startService(startServiceIntent); }}

    onStartCommand()Un problme subsiste aprs que l'application ait dmarr le service. Typiquement, le service dmarrexcute onCreate() puis onStart() qui va par exemple lancer un Thread pour raliser la tche de fond. Sile service doit tre dtruit par la plate-forme (pour rcuprer de la mmoire), puis est rcr, seule lamthoe onCreate() est appele [API-service].Afin de rsoudre le problme prcdent, une nouvelle mthode a fait son apparition dans les versionsultrieures la version 5 de l'API. La mthode onStartCommand() est trs similaire onStart() maiscette mthode renvoie un entier qui permet d'indiquer au systme ce qu'il faut faire au moment de lar-instanciation du service, si celui-ci a d tre arrt.La mthode peut renvoyer (cf [API-service]):

    START_STICKY: le comportement est similaire aux API

  • Dans les versions ultrieures l'API 5, la commande onStart() se comporte commentonStartCommand() avec un r-appel de la mthode avec un intent null. Pour conserver le comportementobsolte de l'API (pas d'appel onStart()), on peut utiliser le flag START_STICKY_COMPATIBILITY.

    Thread d'excutionLe service invoqu par l'Intent de l'application s'excute dans le thread de l'application. Cela peut treparticulirement ennuyeux si les traitements effectuer sont couteux, par exemple si l'on souhaite faire:

    boolean blop = true;while (blop == true) ;

    On obtient:

    Tche rgulireUne faon de rsoudre le problme prcdent est de sparer le processus de l'application et celui duservice, comme voqu plus loin.S'il s'agit de faire une tche rptitive qui ne consomme que trs peu de temps CPU interfals rgulier,une solution ne ncessitant pas de processus part consiste programmer une tche rptitive l'aided'un TimerTask.

    final Handler handler = new Handler();task = new TimerTask() { public void run() { handler.post(new Runnable() { public void run() { Toast.makeText(AndroService.this, "plop !", Toast.LENGTH_SHORT).show(); } });}};timer.schedule(task, 0, 5000);

    La cration du TimerTask est particulirement tarabiscote mais il s'agissait de rsoudre le problme dulancement du Toast. Pour des cas sans toast, un simple appel new TimerTask() { public void run() {code; } }; suffit.Attention bien dtruire la tche programme lorsqu'on dtruit le service ! (sinon, le thread associ latche programm rest actif).

    Thread d'excution Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 37 / 79

  • public void onDestroy() { // Destruction du service timer.cancel(); }

    DmonstrationDans cette dmonstration, le service local l'application est lanc: il affiche toutes les 5 secondes untoast l'aide d'un TimerTask. Il est visible dans la section running services. En cliquant une seconde foissur le bouton start, deux services s'excutent en mme temps. Enfin, les deux services sont stopps. (cfANX_Demarrage-de-services)

    6.2 Faire cooprer service et activitUn service est souvent paramtr par une activit. L'activit peut tre en charge de (re)dmarrer leservice, d'afficher les rsultats du service, etc. Trois possibilits sont offertes pour faire cooprer serviceet activit frontend:

    utiliser des Intents pour envoyer des informations lier service et activit d'un mme processus dfinir une interface de service en utilisant le langage AIDL

    Lier le service et l'activit peut se faire assez simplement en dfinissant une interface (le contrat decommunication entre le service et l'activit) et en utilisant la classe Binder. Cependant, cela n'estralisable que si le service et l'activit font partie du mme processus.Pour deux processus spars, il faut passer par la dfinition de l'interface en utilisant le langage AIDL. Ladfinition de l'interface permettra l'outil aidl de gnrer les stubs de communication inter processuspermettant de lier une activit et un service.

    Lier activit et service: IBinder[BAS] Pour associer un service une activit, le service doit implmenter la mthode onBind() quirenverra l'application un objet de type IBinder. Au travers de l'objet IBinder, l'application aura accs auservice.

    On implmente donc dans le service:

    private final IBinder ib = new MonServiceBinder();public IBinder onBind(Intent intent) { return ib;}

    et on cre une nouvelle classe MyServiceBinder, de prfrence classe interne l'activit, qui renvoie laclasse associe au service:

    private int infoOfService = 0; // La donne transmettre l'activitprivate class MonServiceBinder extends Binder implements AndroServiceInterface { // Cette classe qui hrite de Binder implmente une mthode // dfinie dans l'interface AndroServiceInterface public int getInfo() { return infoOfService; } }

    Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 38 / 79

  • L'interface, dfinir, dclare les mthodes qui seront accessibles l'application:

    public interface AndroServiceInterface { public int getInfo();}

    Lier activit et service: ServiceConnexionPour lier l'activit au service, un objet de la classe ServiceConnexion doit tre instanci partir del'application. C'est cet objet qui fera le lien entre l'activit et le service. Deux mthodes de cet objetdoivent tre surcharges:

    onServiceConnected qui sera appel lorsque le service sera connect l'application et quipermettra de rcuprer un pointeur sur le binder.

    onServiceDisconnected qui permet de nettoyer les choses cres la connexion, par exemple unpointeur d'attribut de classe sur l'objet Binder.

    private int infoFromService = 0;private ServiceConnection maConnexion = new ServiceConnection() {

    public void onServiceConnected(ComponentName name, IBinder service) { AndroServiceInterface myBinder = (AndroServiceInterface)service; infoFromService = myBinder.getInfo(); } public void onServiceDisconnected(ComponentName name) { }};

    Puis, dans le code de l'activit, on initie la connexion:

    Intent intentAssociation = new Intent(AndroServiceBindActivity.this, AndroService.class);bindService(intentAssociation, maConnexion, Context.BIND_AUTO_CREATE);Toast.makeText(getApplicationContext(), "Info lue dans le service: " + infoFromService, Toast.LENGTH_SHORT).show();unbindService(maConnexion);

    DmonstrationDans cette dmonstration, un service lance un thread qui attendra 4 secondes avant d'enregistrer lavaleur 12 comme rsultat du service. A chaque click du bouton, l'activit se connecte au service pourtoaster le rsultat. (cf ANX_Binding-entre-service-et-activite-pour-un-meme-processus)

    Service au travers d'IPC AIDLLe langage AIDL est trs proche de la dfinition d'interfaces Java EE (mais pas tout fait identique). Ils'agit de dfinir ce que les service est capable de faire et donc, quelles mthodes peuvent tre appeles.Un peu comme un web service, la dfinition de l'interface permettra l'outil AIDL de gnrer des stubs decommunication pour les IPC. Ainsi, une autre application android pourra appeler le service au traversd'IPC.Une interface en AIDL peut par exemple ressembler :

    Lier activit et service: ServiceConnexion Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 39 / 79

  • package andro.jf;

    interface AndroServiceInterface { int getInfo();}

    L'outil aidl va gnrer les stubs correspondants l'interface dans un fichier .java portant le mme nomque le fichier aidl, dans le rpertoire gen.

    // This file is auto-generated. DO NOT MODIFY.package andro.jf;public interface AndroServiceInterface extends android.os.IInterface{public static abstract class Stub extends android.os.Binder implements andro.jf.AndroServiceInterface{private static final java.lang.String DESCRIPTOR = "andro.jf.AndroServiceInterface";...

    Service exposant l'interfaceDans le service, on utilise alors l'implmentation gnre par aidl pour implmenter ce que fait le servicedans la mthode dclare par l'interface:

    private int infoOfService = 0; // La donne transmettre l'activitprivate AndroServiceInterface.Stub ib = new AndroServiceInterface.Stub() { @Override public int getInfo() throws RemoteException { return infoOfService; }};public IBinder onBind(Intent arg0) { return ib;}

    Du ct de l'application, il faut aussi utiliser le code de la stub pour rcuprer l'objet implmentantl'interface (cf ANX_Binding-inter-processus-utilisant-le-langage-AIDL):

    private ServiceConnection maConnexion = new ServiceConnection() { public void onServiceConnected(ComponentName name, IBinder service) { AndroServiceInterface myBinder = AndroServiceInterface.Stub.asInterface(service); try { // stockage de l'information provevant du service infoFromService = myBinder.getInfo(); }

    Il devient alors possible de dclarer le service comme appartenant un autre processus que celui del'activit, i.e. android:process=":p2" (cf. Processus).

    6.3 Processus

    Service exposant l'interface Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 40 / 79

  • [PT] Par dfaut, une application android s'excute dans un processus unique, le processus dit "principal".L'interface graphique s'excute elle aussi au travers de ce processus principal. Ainsi, plus une applicationralisera de traitement, plus la gestion de la programmation devient dlicate car on peut arriver trsrapidemment des problmes de blocage de l'interface graphique par exemple.Il est possible de sparer les composants d'une application en plusieurs processus. Ces composants sontles codes attachs aux tags , , , et de l'application. Par dfaut,l'application (tag ) s'excute dans le processus principal portant le mme nom que lepackage de l'application. Bien que cela soit inutile, on peut le prciser dans le Manifest l'aide de l'attributandroid:process, par exemple:

    Les sous-tags du manifest, c'est--dire les composants de l'applications hritent de cet attribut ets'excutent donc dans le mme process. Si l'on souhaite crer un nouveau process indpendant, on peututiliser l'attribut android:process en prfixant le nom du processus par ":", par exemple:

    Pour cet exemple, le service et l'application sont indpendants. L'avantage est double: l'interfacegraphique pourra s'afficher correctement et si le service plante, cela n'impactera pas le processusprincipal.

    DmonstrationDans cette dmonstration, le service, qui comporte une boucle infinie, s'excute dans un processusindpendant de l'interface principale. Android va tuer le service qui occupe trop de temps processeur, cequi n'affectera pas l'application et son interface (cf ANX_Processus-indpendants).

    Vie des processusAndroid peut devoir arrter un processus cause d'autres processus qui requiert plus d'importance. Parexemple, un service peut tre dtruit car une application gourmande en ressources (navigateur web)occupe de plus en plus de mmoire. Plus classiquement, le processus affect une activit qui n'est plusvisible a de grandes chances d'tre dtruite.Ainsi, une hirarchie d'importance permet de classer le niveau d'importance des processus:

    1. Processus en avant plan (activit en intraction utilisateur, service attach cette activit,BroadCastReceiver excutant onReceive())

    2. Processus visible: il n'interagit pas avec l'utilisateur mais peut influer sur ce que l'on voit l'cran(activit ayant affich une boite de dialogue (onPause() a t appel), service li ces activit"visibles").

    3. Processus de service4. Processus tche de fond (activit non visible (onStop() a t appel)5. Processus vides (ne comporte plus de composants actifs, gards pour des raisons de cache)

    Ainsi, il faut prfrer l'utilisation d'un service la cration d'un thread pour accomplir une tche longue,par exemple l'upload d'une image. On garantit ainsi d'avoir le niveau 3 pour cette opration, mme sil'utilisteur quitte l'application ayant initi l'upload.

    6.4 Threads

    Dmonstration Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 41 / 79

  • Dans le processus principal, le systme cr un thread d'excution pour l'application: le thread principal. Ilest, entre autre, responsable de l'interface graphique et des messages/notifications/evnements entrecomposants graphiques. Par exemple, l'vnement gnrant l'excution de onKeyDown() s'excute dansce thread.Ainsi, si l'application doit effectuer des traitements longs, elle doit viter de les faire dans ce thread.Cependant, il est interdit d'effectuer des oprations sur l'interface graphique en dehors du thread principal(aussi appel UI thread), ce qui se rsume dans la documentation sur les threads par deux rgles:

    Do not block the UI thread Do not access the Android UI toolkit from outside the UI thread

    L'exemple ne pas faire est donn dans la documentation et recopi ci-dessous. Le comportement estimprvisible car le toolkit graphique n'est pas thread-safe.

    public void onClick(View v) { // DO NOT DO THIS ! new Thread(new Runnable() { public void run() { Bitmap b = loadImageFromNetwork("http://example.com/image.png"); mImageView.setImageBitmap(b); } }).start();}

    Threads et interface graphiqueAndroid fournit des mthodes pour rsoudre le probme prcdemment voqu. Il s'agit de crer desobjets excutables dont la partie affectant l'interface graphique n'est pas excute mais dlgue l'UIthread pour excution ultrieure.Par exemple, un appel la mthode View.post(Runnable) permet de raliser cela et donne, pourl'exemple prcdent:

    public void onClick(View v) { new Thread(new Runnable() { public void run() { final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png"); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start();}

    La documentation donne les quelques mthodes utiles pour ces cas dlicats:

    Activity.runOnUiThread(Runnable) View.post(Runnable) View.postDelayed(Runnable, long)

    6.5 Bilan: services, processus et threads

    Threads et interface graphique Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 42 / 79

  • Par dfaut, un service s'excute donc dans le mme processus de l'application, dans l'UI thread. Garderle service dans le processus de l'application en le changeant de thread apparait peut cens, sauf s'il s'agitd'un service trs court dont le but est de librer l'interface graphique. Cependant, dans un tel cas, est-ilvraiment ncessaire de raliser un service ? Un thread aurait suffit.Pour une tche longue, survivant la fermeture de l'application principale, tel que l'upload d'un postgoogle+, un service ayant un processus indpendant est appropri.La difficult de la sparation du service et de l'application rside dans la difficult de l'interaction de cesdeux composants. Il faut alors utiliser les mcanismes prvus dans Android pour faire cooprer ces deuxentits l'aide de l'objet IBinder ou d'IPC AIDL.

    Les services comme dmons ?Je ne rsiste pas au plaisir de vous citer une discussion du googlegroup android-developer [LSAS], propos des services persistants, ressemblant des dmons systmes:R. Ravichandran> I have a need to create a background service that starts up during the system boot up,and keeps running until the device is powered down. There is no UI or Activity associated with this.Dianne Hackborn> Mark answered how to do this, but please: think again about whether you really needto do this. Then think another time. And think once more. And if you are really really absolutely positivelysure, this what you want to do, fine, but realize --On current Android devices, we can keep only a small handful of applications running at the same time.Having your application do this is going to going to take resources from other things that at any particularpoint in time would be better used elsewhere. And in fact, you can be guaranteed that your service will-not- stay running all of the time, because there is so much other stuff that wants to run (other backgroundservices that are only running when needed will be prioritized over yours), or needs more memory forwhat the user is actually doing (running the web browser on complicated web pages is a great way to kickbackground stuff out of memory).We have lots of facilities for implementing applications so they don't need to do this, such as alarms, andvarious broadcasts from events going on in the system. Please please please use them if at all possible.Having a service run forever is pretty close to the side of evil.

    Les services comme dmons ? Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 43 / 79

  • 7 Connectivit7.1 Tlphonie 44

    Passer ou filtrer un appel 44Envoyer et recevoir des SMS 45

    7.2 Rseau 46Grer le rseau Wifi/Mobile 46

    7.3 Bluetooth 46S'associer en bluetooth 47Utiliser le rseau 47

    7.4 Localisation 48Coordonnes 48Alerte de proximit 49

    7.5 Capteurs 49Lecture des donnes 49

    7.1 TlphonieLes fonctions de tlphonie sont relativement simples utiliser. Elles permettent de rcuprer l'tat de lafonction de tlphonie (appel en cours, appel entrant, ...), d'tre notifi lors d'un changement d'tat, depasser des appels et de grer l'envoi et rception de SMS.L'tat de la tlphonie est gr par la classe TelephonyManager qui permet de rcuprer le nom del'oprateur, du tlphone, et l'tat du tlphone. Pour lire ces informations, il est ncessaire de disposerde la permission android.permission.CALL_PHONE (cf Contrler les actions permises).

    TelephonyManager tel = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);int etat = tel.getCallState();if (etat == TelephonyManager.CALL_STATE_IDLE) // RASif (etat == TelephonyManager.CALL_STATE_RINGING) // Le tlphone sonneString SIMnb = tel.getSimSerialNumber();

    Il est aussi possible d'tre notifi d'un changement d'tat en utilisant un couteur:

    public class Ecouteur extends PhoneStateListener { public void onCallStateChanged(int etat, String numero) { super.onCallStateChanaged(etat, numero) if (etat == TelephonyManager.CALL_STATE_OFFHOOK) // Le tlphone est utilis}

    Passer ou filtrer un appel

    7 Connectivit Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 44 / 79

  • Il est bien sr possible de passer un appel ou de dlguer l'appel, ces deux actions tant ralises avecun Intent (attention aux permissions):

    Uri telnumber = Uri.parse("tel:0248484000");Intent call = new Intent(Intent.ACTION_CALL, telnumber);startActivity(call);

    Uri telnumber = Uri.parse("tel:0248484000");Intent call = new Intent(Intent.ACTION_DIAL, telnumber);startActivity(call);

    (TODO: revoir) Pour filtrer l'appel, dans le but de loguer une information ou grer l'appel, il faut poser unintent filter:

    Envoyer et recevoir des SMSSi la permission android.permission.SEND_SMS est disponible, il est possible d'envoyer des SMS autravers de SmsManager:

    SmsManager manager = SmsManager.getDeault();manager.sendTextMessage("02484840000", null, "Coucou !", null, null);

    Inversement, il est possible de crer un filtre d'Intent pour recevoir un SMS qui sera gr par un broadcastreceiver. L'action prciser dans le filtre d'Intent du receveur estandroid.provider.Telephony.SMS_RECEIVED:

    Puis, le dbut du code du broadcast receiver est par exemple:

    public final class MyBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(android.provider.Telephony.SMS_RECEIVED)) { String val = extra.getString("extra"); Object[] pdus = (Object[]) intent.getExtras().get("pdus"); SmsMessage[] messages = new SmsMessage[pdus.length]; for (int i=0; i < pdus.length; i++) messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);}}}

    Envoyer et recevoir des SMS Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 45 / 79

  • 7.2 Rseau(cf ANX_Rseau) Le rseau peut tre disponible ou indisponible, suivant que le tlphone utilise uneconnexion Wifi, 3G, bluetooth, etc. Si la permission android.permission;ACCESS_NETWORK_STATEest dclare, la classe NetworkInfo (depuis ConnectivityManager) permet de lire l'tat de la connexionrseau parmis les constantes de la classe State: CONNECTING, CONNECTED, DISCONNECTING,DISCONNECTED, SUSPENDED, UNKNOWN.

    ConnectivityManager manager = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);NetworkInfo net = manager.getActiveNetworkInfo();if (net.getState().compareTo(State.CONNECTED) // Connect

    Il est possible de connatre le type de la connexion:

    int type = net.getType();

    Le type est un entier correspondant, pour l'instant, au wifi ou une connexion de type mobile (GPRS, 3G,...).

    ConnectivityManager.TYPE_MOBILE: connexion mobile ConnectivityManager.TYPE_WIFI: wifi

    Grer le rseau Wifi/MobileLe basculement entre les types de connexion est possible si la permission WRITE_SECURE_SETTINGSest disponible. On utilie alors la mthode setNetworkPreference sur l'objet ConnectivityManager pourlui donner l'entier correspondant au type de connexion voulu. Par exemple:

    manager.setNetworkPreference(ConnectivityManager.TYPE_WIFI);

    L'accs au rseau wifi est grable depuis une application, ce qui permet d'allumer ou de couper le wifi.L'objet WifiManager permet de raliser cela.

    WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);if (!wifi.isWifiEnabled()) wifi.setWifiEnabled(true);

    Les caractristiques de la connexion Wifi sont accessibles par des appels statiques des mthodes deWifiManager:

    force du signal projet sur une chelle [0,levels]: WifiManager.calculateSignalLelvel(RSSI ?,levels)

    vitesse du lien rseau: info.getLinkSpeed() les points d'accs disponibles: List pa = manager.getScanResults()

    7.3 BluetoothLe bluetooth se gre au travers de principalement 3 classes:

    BluetoothAdapter: similaire au WifiManager, cette classe permet de grer les autres appareilsbluetooth et d'initier les communications avec ceux-ci.

    7.2 Rseau Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 46 / 79

  • BluetoothDevice: objet reprsentant l'appareil distant. BluetoothSocket et BluetoothServerSocket: gre une connexion tablie.

    Pour pouvoir utiliser les fonctionnalits bluetooth, il faut activer les persmissionsandroid.permission.BLUETOOTH et android.permission.BLUETOOTH_ADMIN pour pouvoir chercherdes appareils ou changer la configuration bluetooth du tlphone.

    BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();if (!bluetooth.isEnabled()){ Intent launchBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(launchBluetooth);}

    S'associer en bluetoothPour pouvoir associer deux appareils en bluetooth, il faut que l'un d'eux soit accessible (s'annonce) auxautres appareils. Pour cela, l'utilisateur doit autoris le mode "dcouverte". L'application doit donc ledemander explicitement via un Intent:

    Intent discoveryMode = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);discoveryMode.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 60);startActivity(discoveryMode);

    A l'inverse, si un appareil externe diffuse une annonce de dcouverte, il faut capturer les intents recus enbroadcast dans le mobile:

    public final class BluetoothBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); BluetoothDevice appareil = null; if (action.equals(BluetoothDevice.ACTION_FOUND)) appareil = (BluetoothDevice)intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); }}

    Enfin les appareils associs se parcourent l'aide d'un Set:

    Set s = bluetooth.getBondedDevices(); for (BluetoothDevice ap : s) Toast.makeText(getApplicationContext(), "" + ap.getName(), Toast.LENGTH_LONG).show();

    Utiliser le rseauDe nombreuses mthodes de dveloppement permettent d'exploiter le rseau. Elles ne sont pasrapelles en dtail ici (ce n'est pas l'objet du cours) et elles sont de toutes faons dj connues:

    HTTP: HttpClient, httpResponse SOAP: SoapObjet, SoapSerializationEnvelope REST:

    JSON: JSONObject XML: DocumentBuilder

    S'associer en bluetooth Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 47 / 79

  • Sockets: Socket, ServerSocket Bluetooth: BluetoothSocket, BluetoothServerSocket

    7.4 Localisation(cf ANX_Localisation) Comme pour le rseau, Android permet d'utiliser plusieurs moyens de localisation.Cela permet de rendre transparent l'utilisation du GPS ou des antennes GSM ou des accs au Wifi. Laclasse LocationManger permet de grer ces diffrents fournisseurs de position.

    LocationManager.GPS_PROVIDER: fournisseur GPS LocationManager.NETWORK_PROVIDER: fournisseur bas rseau

    La liste de tous les fournisseurs s'obtient au travers de la mthode getAllProviders() ougetAllProviders(true) pour les fournisseurs activs:

    LocationManager manager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);List fournisseurs = manager.getAllProviders();for (String f : fournisseurs) { Toast.makeText(getApplicationContext(), "" + f, Toast.LENGTH_SHORT).show(); if (f.equals.(LocationManager.GPS_PROVIDER)) ...

    }

    Les permissions associes pour la localisation sont:

    android.permission.ACCESS_FINE_LOCATION via le GPS android.permission.ACCESS_COARSE_LOCATION via le rseau

    CoordonnesA partir du nom d'un fournisseur de position actif, il est possible d'interroger la dernire localisation enutilisant l'objet Location.Location localisation = manager.getLastKnownLocation("gps");Toast.makeText(getApplicationContext(), "Lattitude" + localisation.getLatitude(), Toast.LENGTH_SHORT).show();Toast.makeText(getApplicationContext(), "Longitude" + localisation.getLongitude(), Toast.LENGTH_SHORT).show();

    Il est possible de ragir un changement de position en crant un couteur qui sera appel intervalsrguliers et pour une distante minimum donne:

    manager.requestLocationUpdates("gps", 6000, 100, new LocationListener() {

    public void onStatusChanged(String provider, int status, Bundle extras) { } public void onProviderEnabled(String provider) { } public void onProviderDisabled(String provider) { } public void onLocationChanged(Location location) { // TODO Auto-generated method stub }});

    7.4 Localisation Ensi de Bourges - Filire STI

    Dveloppement sous Android - J.-F. Lalande 48 / 79

  • Alerte de proximitIl est possible de prparer un venement en vu de ragir la proximit du tlphone une zone. Pourcela, il faut utiliser la mthode addProximityAlert de LocationManager qui permet d'enregistrer un Intentqui sera envoy lorsque des conditions de localisation sont runies. Cette alerte possde une dured'expiration qui la dsactive automatiquement. La signature de cette mthode est:addProximityAlert(double latitude, double longitude, float radius, long expiration, PendingIntentintent)Il faut ensuite filtrer l'intent prpar:

    IntentFilter filtre = new IntentFilter(PROXIMITY_ALERT);registerReceiver(new MyProximityAlertReceiver(), filtre);

    La classe grant l'alerte est alors:

    public class MyProximityAlertReceiver extends BroadcastReiceiver { public void onReceive(Context context, Intent intent) { String key = LocationManager.KEY_PROXIMITY_ENTERING; Boolean entering = intent.getBooleanExtra(key, false);}}

    7.5 Capteurs(cf ANX_Capteurs) Android introduit la gestion de multiples capteurs. Il peut s'agir de l'accelromtre, dugyroscope (position angulaire), de la luminosit ambiante, des champs magntiques, de la pression outemprature, etc. En fonction, des capteurs prsents, la classe SensorManager permet d'accder auxcapteurs disponibles. Par exemple, pour l'accelromtre:

    SensorManager manager = (SensorManager)getSystemService(SENSOR_SERVICE);manager.registerListener( new SensorEventListener() { public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub } public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub }} , manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) , SensorManager.SENSOR_DELAY_UI );}

    Quand l'accelromtre n'est plus utilis, il doit tre dsenregistr l'aide de:

    manager.unregisterListener( pointeur ecouteur , manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) );

    La frquence d'interrogation influe directement sur l'nergie consomme. Cela va du plus rapide possiblepour le systme une frquence faible: SENSOR_DELAY_FASTEST < SENSOR_DELAY_GAME