Android: Introduction, présentation jean-michel Douin, douin au cnam point fr version : 20 Février 2013 Notes de cours Android_Introduction 1 Sommaire • Intergiciel (middleware) – Les éléments de base • Android OS comme intergiciel – Applications et évènements gérés par le middleware – Approche déclarative – Composants, classes de base • • • • • Activity, BroadcastReceiver, Service, ContentProvider, Intent. – Patrons de utilisés • • • • • • • Android_Introduction Fabrique méthode MVC, Modèle Vue Contrôleur Façade Procuration Médiateur Stratégie … 2 Bibliographie utilisée… à compléter Mobile Middleware, Architecture, Patterns and Practice, Sasu Tarkoma,ed. Wiley 2009 [Sheng-De Wang] Le point de départ de ce support Auteur: Prof. Sheng-De Wang http://intw2-2010.cs.pu.edu.tw/a1.ppt http://0xlab.org/~jserv/android-binder-ipc.pdf [Sch06]Le site de douglas Schmidt http://www.cs.wustl.edu/~schmidt/patterns.html ce site http://www.cs.wustl.edu/~schmidt/POSA/ [Kra06] La présentation de S. Krakowiak faite à l ’école d ’été ICAR 2006 http://sardes.inrialpes.fr/ecole/2006/ http://www2.lifl.fr/icar/Chapters/Intro/intro.html [VKZ05] le site de Uwe Zdun : http://www.infosys.tuwien.ac.at/Staff/zdun/ ce livre : http://www.infosys.tuwien.ac.at/Staff/zdun/remotingPatterns/index.html ce support http://www.infosys.tuwien.ac.at/Staff/zdun/teaching/evs/evs.pdf informations générales http://www.edlin.org/cs/patterns.html http://www.powershow.com/view/133aa5MjUxY/Mobile_Middleware_Course_Principles_and_Patterns_Sasu_Tarkoma_powerpoint_ppt_presentation http://developer.android.com/resources/index.html Android_Introduction 3 Introduction • Intergiciel, fonctionnalités attendues • Android – Un premier aperçu en quelques diapositives • Le vocable • Architecture logicielle • Le simulateur, les API • Une démonstration Android_Introduction 4 Tendances, historique INTERNETWORKING ARCH RTP TFTP FTP MIDDLEWARE ARCH HTTP Middleware Applications TELNET DNS UDP Middleware Services TCP IP Middleware Fibre Channel Ethernet ATM 20th Century Solaris FDDI Win2K VxWorks Linux LynxOS 21st Century • [Sch06] Android_Introduction 5 Fonctions attendues de l ’intergiciel • de [Kra06] • Proposer une API de haut Niveau – Masquer l ’hétérogénéité – Rendre la répartition invisible – Faciliter la programmation répartie Fonctions orientées: Réseau « fixe », internet, web, SOA Android_Introduction 6 Intergiciel et mobile • Sécurité – Confidentialité, intégrité, contrôle des informations par l’utilisateur • Mobile comme « Baie d’accueil » des applications – Installation, au sein d’un « sandbox » • Liste des applications, annuaire, – Eligibilité, sélection de la « bonne » application, – Découverte au « run time » d’un service • Déploiement, mise à jour, maintenance – Substitution d’une application par une autre • Communication – Réseaux • communications synchrones, asynchrones, interruptions de services • Notifications inhérentes: sms, push … • Persistance – Embarquée • Consommation – Batterie Android_Introduction 7 Android • Sécurité – Linux, processus … • Mobile comme « Baie d’accueil » des applications – Un processus une application une DVM (Dalvik Virtual Machine) • (Vue logique), « sandbox » inhérent • Déploiement, mise à jour, maintenance – Prise en charge par l’intergiciel • Communication – Interne, externe -> intergiciel, sms, push … • Persistance – -> intergiciel, SQLLite Android_Introduction 8 Android les grandes lignes • Composants Android • Outils de Développement • Architecture Logicielle • Développement – en java avec quelques directives et configurations en syntaxe XML • Un exemple, une démonstration – Un exemple en quelques lignes de java et d’XML Android_Introduction 9 Composants Android • Linux – Processus / DVM / Application • Framework de déploiement d’applications – De nombreuses librairies, • Navigateur intégré, WebKit ( webkit utilisé par safari, Google Chrome…) • SQLite • En natif, pilotes – Dépendant du matériel • • • • • Android_Introduction GSM Bluetooth, EDGE, 3G, WiFi Caméra, GPS, boussole et accéléromètre Température, … 10 Outils de développement • SDK Android –En ligne de commandes –Plug-in sous eclipse –Émulateur –Débogueur –Traces fines d’exécution –Tests unitaires –Outils de mise au point •Mesure de mémoire et performance Android_Introduction 11 Framework ou baie d’accueil des applications • Source : http://www.linuxjournal.com/ Android_Introduction 12 Architecture et API http://developer.android.com/guide/basics/what-is-android.html Android_Introduction 13 Développement • Développement – En java, configurations en syntaxe XML • Une configuration de l’application – AndroidManifest.xml • Une déclaration de ressources en XML – comme l’IHM ou des String » res/layout/hello_web_view.xml » res/values/strings.xml Android_Introduction 14 Développement 1/2 Fichier de configuration, AndroitManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="test.biblio" android:versionCode="1" android:versionName="1.0"> <uses-permission android:name="android.permission.INTERNET" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Demo" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> Android_Introduction 15 Premier exemple support Sheng Wang package com.android.webviews; import import import import import android.app.Activity; android.os.Bundle; android.view.KeyEvent; android.webkit.WebView; android.webkit.WebViewClient; public class HelloWebView extends Activity { /** Called when the activity is first created. */ WebView webview; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); webview = (WebView) findViewById(R.id.webview); webview.getSettings().setJavaScriptEnabled(true); webview.loadUrl("http://www.cnam.fr"); webview.setWebViewClient(new HelloWebViewClient()); } Android_Introduction 16 Suite de l’exemple @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) { webview.goBack(); return true; } return super.onKeyDown(keyCode, event); } private class HelloWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } } } Android_Introduction 17 Démonstration • Démonstration Puis • Les composants essentiels Android_Introduction 18 Vocabulaire • Les Essentiels – Activity • Une activité est associé à une IHM – BroadcastReceiver • Réception d’un message transmis par Android – Service • Une tache de fond sans IHM – ContentProvider • La persistance des données – Intent • Les notifications – IntentFilter • Les filtres des notifications candidates Android_Introduction 19 Introduction … Classes • Activity – Associée à une interface utilisateur • Cycle de vie (démarrée, en pause, arrêtée, détruite…) – Peut démarrer d’autres activités, émet des évènements(intentions, intent) • Une configuration de type XML, permissions, librairies, • BroadcastReceiver – Bus de messages – Émission et réception d’intentions (intent) • Service – Pas d’interface, un service à rendre, en tâche de fond – Intention de servir, langage commun aux clients et au service • ContentProvider – Données rendues persistantes ( pour d’autres applications) – Un fichier, base SQLite • Intent – Notifications, • IntentFilter – Critères de sélection, éligibilité, mécanisme de résolution Android_Introduction 20 Application • Une application peut être constituée de plusieurs écrans, • A chaque écran lui correspond une activité, • Une activité hérite et redéfinit certaines méthodes – onCreate, -> …, onPause, -> …, onStop, ->…onDestroy, -> … • Android se charge des appels de ces méthodes – Un état de l’activité est donc induit par l’exécution de ces méthodes • Inversion de contrôle – (cf. M.Fowler) http://martinfowler.com/articles/injection.html – Android impose un cycle de vie, un état de l’activité Android_Introduction 21 Architecture, vocabulaire • Source : http://developer.android.com/guide/topics/fundamentals.html • Application – – – – Activity Service ContentProvider BroadcastReceiver Android_Introduction 22 public class android.app.Activity package android.app; public class Activity extends ApplicationContext { protected void onCreate(Bundle savedInstanceState){ protected void onStart(); protected void onRestart(); protected void onResume(); protected void onPause(); protected void onStop(); protected void onDestroy(); … etc … } induit un cycle de vie imposé par le « framework » Android_Introduction 23 Inversion de Contrôle… Rappel Activités activité_1 Activité 2 Activité 3 onCreate(..) onStart(); …activité_1 = new Activité_1(); activité_1.onCreate(); activité_1.onStart(); …. Android, middleware public class Activity extends ApplicationContext { protected void onCreate(Bundle savedInstanceState); protected void onStart(); …..} http://developer.android.com/reference/android/app/Activity.html Android_Introduction 24 Le cycle de vie d’une activité • Séquencement des appels imposé par le système Android_Introduction 25 Activité son état • • http://inandroid.in/archives/tag/activity-lifecycle Attention une application dans l’état Paused ou Stopped peut être supprimé par Android Android_Introduction 26 Un exemple: une très petite IHM Une « IHM » • Un bouton, un écouteur, un clic et l’heure est affichée ! • En approche traditionnelle • Tout est codé en Java IHM comprise – En approche déclarative • Android_Introduction Usage d’XML pour la configuration, de java pour l’utilisation 27 Activity Un Click et l’heure est actualisée import import import import import android.app.Activity; android.os.Bundle; static android.view.View.OnClickListener ; android.widget.Button; java.util.Date; public class Now extends Activity implements OnClickListener { private Button buttonNow; @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); buttonNow = new Button(this); // <- un bouton buttonNow.setOnClickListener(this);// <- un écouteur auprès de cette vue setContentView(buttonNow); // <- le bouton devient la vue, l’écran } public void onClick(View view) { // <- à chaque click buttonNow.setText(new Date().toString()); } } Est-ce une vue apparentée swing Et ici un MVC à lui tout seul … ? discussion Android_Introduction 28 Activity-bis Un Click et l’heure est actualisée • Approche « déclarative », – res/layout/activity_now.xml – Balise XML <Button attribut android:onClick – Le fichier res/layout/activity_now.xml <Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/buttonNowId" android:layout_width="match_parent" android:layout_height="match_parent" android:text="Now" android:onClick="onClick" /> Android_Introduction 29 L’activity devient (version déclarative) public class NowActivity extends Activity { private Button buttonNow; protected void onCreate(Bundle bundle) { super.onCreate(bundle); // Vue issue du fichier XML, fichier R.java est généré automatiquement // R.java installe un accès en java aux ressources décrite en XML setContentView(R.layout.activity_now); // Button, identifié par un Id, est issu du fichier XML buttonNow = (Button)findViewById(R.id.buttonNowId); } // l’attribut onClick a ce nom de méthode comme valeur public void onClick(View view) { buttonNow.setText(new Date().toString()); } } Android_Introduction 30 Discussion MVC ? • Démonstration • Discussion MVC ? – Modèle ? – Vue ? – Contrôleur ? Android_Introduction 31 MVC discussion suite • http://java.sun.com/blueprints/guidelines/designing_enterprise_applications/introduction/summary/index.html Android_Introduction 32 Retour sur les API • Android: un ensemble d’API – Activity Manager – View System listes, boutons,… navigateur (WebView) – http://developer.android.com/guide/basics/what-is-android.html Android_Introduction 33 View System • Un usage du patron composite Android_Introduction 34 View (Component), ViewGroup (Composite) Source: [Sheng-De Wang] C’est bien un composite Android_Introduction 35 Détaillé: Composite Source: [Sheng-De Wang] Exemple précédent setContentView(buttonNow); Android_Introduction 36 Une calculette: Layout, View , Button… LinearLayout TextView EditText TableRow Button ProgressBar • Description de cette interface en XML – Fichier Android_Introduction res/layout/main.xml 37 Interface, IHM : Approche déclarative ./res/ • Chaque composant possède un id (android:id= "@+id/push") Android_Introduction 38 Architecture: la calculette, un classique • Le Modèle – La calculette munie de ses opérations (+,-,/,*,…) • Les sources du modèle sont ici – http://douin.free.fr/tp4Calculette/ – La calculette hérite de la classe java.util.Observable • La Vue – L’IHM affichage, zone de saisie, boutons … • Le Contrôleur – Le comportement de l’IHM Android_Introduction 39 MVC nouvelle discussion Classes déjà écrites Calculette Modèle update(.. « XML » IHM extends java.util.Observable implements CalculetteI enter, add, sub, … CalcActivity Contrôleur extends android.app.Activity implements java.util.Observer Listeners Android • L’activity Android est une vue du Modèle Calculette (implements Observer) • L’activity Android est le contrôleur de l’IHM décrite en XML (extends Android_Introduction Activity) 40 Résumé: Application, Activity … – Un processus linux contient une application, – Une application, peut contenir une ou plusieurs activités, – Une activité se trouve dans un certain état, cf. cycle de vie Android_Introduction 41 Communication inter applications • Intent, comme notification – Souscription/Publication – Appeler, déclencher une autre activité • Avec éventuellement des paramètres et des résultats attendus – L’intergiciel sélectionne la « bonne application » • Selon les critères exigés par le souscripteur • Critères précisés lors de la publication – Nécessaire adéquation à l’exécution services fournis / services requis Android_Introduction 42 Patron Publish-Subscribe/Intent & Context • Source: http://roboticswikibook.org, rappel Android_Introduction 43 Sous Android • Mediator, classe Context – http://developer.android.com/reference/android/content/Context.html • Subscriber, classe BroadcastReceiver – http://developer.android.com/reference/android/content/BroadcastReceiver.html • X,Y les thèmes, classe Intent – http://developer.android.com/reference/android/content/Intent.html • IntentFilter – http://developer.android.com/reference/android/content/IntentFilter.html Android_Introduction 44 Un mobile à l’intention de téléphoner • Intent • Démarrer une activité prédéfinie : téléphoner, légitime… public class TelephonerActivity extends Activity { @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.activity_now); } public void onClick(View view) { Intent intent = new Intent(); intent.setAction("android.intent.action.DIAL"); this.startActivity(intent); } } • android.app.Activity extends ….. extends android.content.Context Android_Introduction 45 Téléphoner: le souscripteur a déjà souscrit • Discussions Intent intent = new Intent(); intent.setAction("android.intent.action.DIAL"); – À la recherche de la bonne action, application • Ici un nom ("android.intent.action.DIAL"); • • • • Plusieurs élus possibles Composant logiciels, Maintenance … • Démonstration ! Android_Introduction 46 Recevoir un SMS, le souscripteur – Le souscripteur hérite de android.content.BroadcastReceiver • Et implémente ce qu’il faut faire lors de la notification public class ReceiverSMS extends BroadcastReceiver{ // à chaque SMS reçu public void onReceive(Context ctxt, Intent intent) { // } } // à chaque SMS reçu ? Adéquation intention (Intent) ReceiverSMS par un filtre (IntentFilter) Réalisation : tout en java ou directives XML … Android_Introduction 47 Recevoir un SMS, le souscripteur – Tout java: un receveur/souscripteur au sein d’une activité public class SMSActivity extends Activity { private static class ReceiverSMS extends BroadcastReceiver{ // à chaque SMS reçu public void onReceive(Context ctxt, Intent intent) { // … }} protected void onCreate(Bundle bundle) { super.onCreate(bundle); final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED"; IntentFilter filter = new IntentFilter(SMS_RECEIVED); registerReceiver(new ReceiverSMS(), filter); setContentView(R.layout.activity_now); } Android_Introduction 48 Le receveur en déclaratif <receiver android:name=".ReceveurDeSMS" android:exported="true" > <intent-filter android:priority="999"> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> public class ReceveurDeSMS extends BroadcastReceiver{ // à chaque SMS reçu public void onReceive(Context ctxt, Intent intent) { // } } Android_Introduction 49 Publish/Subscribe Plusieurs Receveurs/souscripteurs, l’un deux peut arrêter la propagation, une priorité peut être affecté à chaque receveur La liste des souscripteurs serait-elle une Chaîne de responsabilités avec priorités ? Démonstration 1) un receveur de SMS 2) avec deux receveurs Scénario: si le contenu du message contient « vibrator », le mobile vibre et le message est intercepté ! Android_Introduction 50 Patron publish/subscribe « Over the air » • Google Cloud Messaging • Android 2.2 • Message <= 4ko • Trafic illimité – Nécessite une inscription auprès de Google • Avec de préférence un compte gmail dédié Android_Introduction 51 Publish/Subscribe « Over the air » • 1) Souscription Android_Introduction 52 Publish/Subscribe « Over the air » • 2) Publication Android_Introduction 53 Architecture : Objectifs • Un client, tout système connecté – S’adresse au serveur Google qui se chargera de publier auprès des mobiles • Mobiles ayant préalablement souscrits • Android_Introduction Mise en œuvre : une librairie toute prête, en un appel de méthode 54 Publish/Subscribe « Over the air » • 3) Notification Android_Introduction 55 Architecture : Mise en œuvre, inscription 1)inscription GCM 2)identifiant 3) dépôt de l’identifiant • Chaque participant – Doit avoir un compte google gmail – S’inscrit auprès de GCM, en retour un identifiant lui est attribué • Un serveur mémorise, l’identifiant retourné par GCM – Un serveur au protocole HTTP de préférence Android_Introduction 56 Architecture : Mise en œuvre, inscriptions • • • • • • id1 id2 id3 … … … • Le serveur contient une liste des identifiants • Un identifiant par application • Exemple : Une liste d’identifiants accessible depuis le web • http://jfod.cnam.fr/registration/demo/?cmd=toString Android_Introduction 57 Architecture : Mise en œuvre, publications 1) Demande de la liste 2) [id1, id2, id3, ……] 3) Demande de publication [id1, id2, id3, ……] + message message id1 id2 message message • id3 Publication par tout système connecté 1, 2) Demande et obtention de la liste des identifiants, 3) Envoi de cette liste au serveur Google/GCM accompagnée du message à transmettre GCM se charge de publier le message, de le ré-émettre, de le conserver … Android_Introduction 58 Architecture : publications message id1 id2 message message id3 • Chaque mobile, ayant préalablement souscrit, est notifié – C’est un « Receiver », prêt à l’emploi, qui est déclenché sur chaque mobile Android_Introduction 59 Démonstration • • • • • • id1 id2 id3 … … … – Service web • Interrogations – http://jfod.cnam.fr/registration/demo/?cmd=toString – http://jfod.cnam.fr/registration/demo/?cmd=list • Publication – http://jfod.cnam.fr/registration/demo/?cmd=send&message=hello_GCM • http://jfod.cnam.fr/cgm/demo.html Android_Introduction 60 Démonstration • Installez cette application sur vos mobiles ou sur votre émulateur – L ’application Android (souscription et publication) • Patience la durée de la découverte de votre mobile ou émulateur peut prendre quelques minutes • http://jfod.cnam.fr/cgm/GCM_Client_Demo.apk – Modeste interface web de tests… • http://jfod.cnam.fr/cgm/demo.html Android_Introduction 61 Les services: Sommaire – Services • Cycle de vie – création, démarrage et arrêt • Service local • Service « global », AIDL (Android Interface Description Language) Note: A chaque thème un exemple complet et une démonstration Avertissement : les démonstrations ne sont pas garanties… Android_Introduction 62 Sommaire : Architectures présentées 1/3 Un processus Une DVM Une activité Un service compteur • Service local, une activité, un service – Échange de données • Envoi des paramètres depuis l’activité par une intention • Réception des résultats – Simplifié, variable globales, ici le compteur (même machine) – Usage des classes Messenger et Handler Android_Introduction 63 Sommaire : Architectures présentées 2/3 Un processus Une DVM Un processus Une DVM Une activité Un service compteur • Un service global, une activité – Échange de données • Envoi depuis l’activité par une intention • Réception des résultats – Messenger et handler – ServiceConnection, accès via un mandataire AIDL Android_Introduction 64 Bibliographie utilisée • http://developer.android.com/reference/android/app/Service.html • http://www.vogella.com/articles/AndroidServices/article.html • http://grail.cba.csuohio.edu/~matos/notes/cis-493/lecture-notes/Android-Chapter22Services.pdf • http://davanum.wordpress.com/2007/12/15/android-listen-for-incoming-sms-messages/ • À compléter Android_Introduction 65 Service • En tâche de fond – Pas d’IHM • • • • • J’écoute un fichier audio mp3, pendant que je navigue sur le web, Dès que je m’empare du mobile, une sonnerie retentit, Les coordonnées GPS sont envoyées régulièrement, Dès que je m’approche d’une zone dangereuse mon mobile s’éteint, … • Toujours disponibles – Locaux • Service personnel, inaccessible pour les autres applications – Service, Intent, IntentService » En accès restreint – « Distants » • Accessible aux autres applications – Langage commun AIDL – Recherche du service, IBinder, Connection Android_Introduction 66 Services : cycle de vie, deux styles Quelque soit l’architecture choisie Usage de startService Android_Introduction Usage de bindService 67 Service local, schéma des exemples • Un service local – Une horloge • Un compteur est incrémenté chaque seconde …tic…tic…tic…tic…tic…tic – Lecture synchrone du compteur de tics • À son initiative, le client questionne … (combien de tics ?) – Un message contenant le nombre de tics est envoyé par le service • Réception asynchrone par le client … (veuillez recevoir ce nombre de tics, svp) – A chaque incrémentation du compteur une notification a lieu • Dans la barre des notifications… (le compteur a changé de valeur ?) – A chaque incrémentation un envoi aux receveurs agréés est effectué • Envois asynchrones aux multiples receveurs éventuel selon un ordre Android_Introduction 68 Les exemples de ce support, suite • Un service global – Un compteur de SMS entrants en trois étapes 1. AIDL, les services, le langage commun entre les clients et le service – Le squelette du programme – Types primitifs et Parcelable 2. Mise en place du receveur de SMS – Liaison receveur et service Android_Introduction 69 Architecture du premier exemple Une activité Le (UI)thread main Un processus Une DVM Un service un thread ticker tic…tic…tic…tic…tic… compteur • De l’activité, – Démarrage du service par startService – accès au compteur de tics par l’appel d’une méthode de classe, lecture de la valeur • Activité : classe ServiceLocalActivity • Service : classe TimeService Android_Introduction 70 Un Service Local, au sein d’une activity • Une horloge – Un compteur est incrémenté chaque seconde …tic…tic…tic…tic…tic…tic • Le fichier Manifest.xml mentionne le service (TimeService) <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="service.local" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".ServiceLocalActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name="TimeService" ></service> </application> </manifest> Android_Introduction 71 Un service local c’est : Une déclaration XML et un héritage de la classe Service Une déclaration • Balise service dans la configuration AndroidManifest.xml – Par défaut le service se trouve dans le même processus que l’activité Une classe au sein de la même application • public class TimeService extends android.app.Service{ – public void onCreate(){…} – public int onStartCommand(Intent intent, int flags, int startId) {…} • onStart appelle cette méthode – public onDestroy{…} Android_Introduction 72 Démarrage du service 1/2 • Au sein de l’activité, – Déclaration de l’intention – Intent intent = new Intent(this, TimeService.class); • this : le contexte • TimeService.class : le service, » dans la même application (un package référencé par Android) • L’intent peut contenir paramètres, exemple – intent.putExtra("pid", android.os.Process.myPid()); Android_Introduction 73 Démarrage et arrêt du service 2/2 • Au sein de l’activité, – Démarrage et arrêt du service, • Cycle de vie du service startService(intent); Démarrage effectif du service, appel de onCreate, onStart->onStartCommand du service stopService(intent); Arrêt du service, appel de onDestroy du service Android_Introduction 74 Schéma de programme du service, 1/3 public class TimeService extends Service { // à la suite de l’appel de startService public void onCreate(){ } // non renseigné dans cette version utilisant startService public IBinder onBind(Intent i) { return null; } Android_Introduction 75 Schéma de programme du service, 2/3 private static Thread ticker; private static AtomicLong count; // suite de l’appel de startService, cf. cycle de vie public int onStartCommand(Intent intent, int flags, int startId) { if(ticker==null){ count = new AtomicLong(); // accès concurrents ticker = new Thread(new Ticker()); // un thread local ticker.start(); } return START_STICKY; // démarrage et arrêt explicites // la constante retournée induit un comportement du service // http://developer.android.com/reference/android/app/Service.html } Android_Introduction 76 Méthode run (le ticker), du service 3/3 // l’horloge et son thread, « du classique » private class Ticker implements Runnable{ public void run(){ while(!ticker.isInterrupted()){ try{ Thread.sleep(1000); count.set(count.longValue()+1L); }catch(Exception e){ return; } } } // accès en lecture, par l’activité public static long getCount(){ return count.get(); } Android_Introduction 77 Le client, une activity, un affichage public class ServiceLocalActivity extends Activity public void onClickStart(View v){ Intent intent = new Intent(this, TimeService.class); intent.putExtra("pid", android.os.Process.myPid()); started = startService(intent) != null; } public void onClickStop(View v){ started = !stopService(new Intent(this, TimeService.class)); } public void onClickGetCount(View v){ if(started) texte.setText("count: " + TimeService.getCount()); else texte.setText("service non démarré"); Méthodes de classe } Même DVM (tout va bien) Android_Introduction 78 Démonstration Android_Introduction 79 Un résumé et la suite • Un service local – Hérite de Service • StartService ou • Une autre écriture est possible avec bindService – L’exemples présenté utilise la même DVM • Accès « simplifié » aux services rendus – Accès par une méthode de classe, • Et maintenant : un service global Android_Introduction 80 Discussion, même DVM ou non • Ici le service partage le même processus que l’activité • Attention • Si nous choisissons, un processus dédié au service – <service android:name="TimeService" android:process= ":timeService"> – </service> – Cela ne fonctionne plus, démonstration … – explication … cf. schéma page suivante Android_Introduction 81 Schéma : processus et DVM Activity TimeService count 5 • • Un seul processus Activity + service Tout va bien en apparence Activity count null TimeService count 5 • Deux processus, deux DVM • Exception !!!! (Le code pour la lecture de count est le même) • L’accès par des variables de classes: peu satisfaisant Android_Introduction 82 help -> recherche sur le web • http://blog.developpez.com/android23/p8571/android/creation_de_ser vice • Utilisation de listener • En conséquence pour un service global un IPC est nécessaire – IPC comme Inter Process Communication – Plusieurs façons de faire • Messenger + Handler • broadcastReceiver • AIDL Android_Introduction 83 Communication entre processus • Solutions – Messenger + Handler • Message inter process • Autorise une communication asynchrone • Un message est envoyé au client, celui-ci est prévenu à l’aide d’un Handler – Un receveur ou plusieurs receveurs • Un ou des receveurs et le bon filtre sont enregistrés • Le service envoie un « intent » et son filtre, – A destination des receveurs agréés, filtrés – Le service devient global • Nécessité d’utiliser AIDL – in, out, inout, et certains types pris en compte, – implements Parcelable pour du sur mesure Android_Introduction 84 Service global : création, démarrage et arrêt • En tache de fond • Toujours disponible • Services globaux – « Distants » • Rmi en plus simple … même machine … • Accessible à tous – Attribut android:exported="true", balise service Android_Introduction 85 activité_1 Activité 2 service Services Applications Un Service à disposition de tous Android, middleware Service distant, – Découverte du service par une intention … – Sérialisation/désérialisation lors du passage de paramètre • Implicite si types primitifs, List et Map, • Explicite par l’implémentation de Parcelable Android_Introduction 86 Un simple service global • Un service accessible par toute application – Avec quelques contraintes • Un langage commun AIDL – AIDL, Android Interface Description Language – Types primitifs de java – String, CharSequence, List (ArrayList coté serveur), Map (HashMap) • Indication du type de passage de paramètre in, out, inout • Sérialisation/désérialisation – Autres classes, elles devront : implements Parcelable • Analogue à Serializable, mais rien n’est implicite Android_Introduction 87 Exemple : compteur de SMS … • Approche incrémentale à l’aide d’un exemple 1. Un service global accessible par tous (Exemple 1) Limité à 3 fonctionnalités élémentaires Démarrer, arrêter, combien ? 1. Nous déjà vu ces commandes quelque part ? 2. Ajout effectif du receveur de messages (Exemple 2) – Mise en œuvre du receveur d’intention standard Démarrer le receveur, arrêter la réception, combien de SMS reçus ? 3. Ajout d’une nouvelle fonctionnalité (Exemple 3 ou une idée de TP) – Le texte d’un sms contient une commande (secrète) qui déclenche l’action correspondante, (envoi de la position…) Android_Introduction 88 Exemple 1 3 fichiers 1. Une interface en AIDL des fonctionnalités distantes • • Sous ensemble de Java, par défaut types primitifs, List, Map Parcelable sinon 2. Une implémentation du service • La souche, le mandataire à destination des clients distants, est générée 3. Une activity de mise en oeuvre – Recherche du service – Connexion avec celui-ci Android_Introduction 89 Exemple un préambule compteur de SMS package seja.android; interface SMSServiceI{ void start(); // démarrage de la réception sms void stop(); // arrêt de celle-ci long received(); // combien de SMS reçus ? } .aidl .java Android_Introduction 90 Service, AIDL (android interface description language) package cnam.android; interface SMSServiceI{ void start(); void stop(); long received(); } /* This file is auto-generated. */ DO NOT MODIFY. package cnam.android; import …; public interface SMSServiceI extends android.os.IInterface{ /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements cnam.android.SMSServiceI{ … Android_Introduction 91 Implémentation du service, SMSService.java public class SMSService extends Service{ // appelée par les clients public IBinder onBind(Intent intent) { return new SMSServiceImplStub(); } private static class SMSServiceImplStub extends SMSServiceI.Stub{ private static long counter; // compteur de sms provisoire public void start() throws RemoteException { Log.i("SMSServiceImplStub","start"); } public void stop() throws RemoteException { Log.i("SMSServiceImplStub","stop"); } public long received() throws RemoteException { synchronized(SMSServiceImplStub.class){ counter++; } return counter; }}} Android_Introduction 92 L’activité cliente du service public class ServiceSMSReceivedActivity extends Activity { private SMSServiceI service; private ConnexionAuServiceSMS connexion; • public void onClickStart(View v){ if(!connecte){ // identification du service Intent serviceIntent = new Intent(); serviceIntent.setClassName("seja.android", "seja.android.SMSService"); // connexion avec le service this.connexion = new ConnexionAuServiceSMS(); // connexion sera déclenchée par l’intergiciel (asynchrone) bindService(serviceIntent, connexion, Context.BIND_AUTO_CREATE); connecte = true; start.setEnabled(false); stop.setEnabled(true); }} Android_Introduction 93 Connexion au service, par android, asynchrone Cf. transparent précédent // connexion avec le service this.connexion = new ConnexionAuServiceSMS(); // connexion sera déclenchée par l’intergiciel (asynchrone) bindService(serviceIntent, connexion, Context.BIND_AUTO_CREATE); private class ConnexionAuServiceSMS implements ServiceConnection{ public void onServiceConnected(ComponentName name, IBinder binder) { // méthode appelée par Abdroid, // service reçoit un mandataire service = SMSServiceI.Stub.asInterface(binder); } public void onServiceDisconnected(ComponentName name) { } } Android_Introduction 94 L’activité cliente connectée public class ServiceSMSReceivedActivity extends Activity { private SMSServiceI service; private ConnexionAuServiceSMS connexion; public void onClickHow(View v){ if(connecte){ try { texte.setText(Long.toString( service.received())); } catch (RemoteException e) { } } Appel de service.received(), Affichage de la valeur 5 ouf… Android_Introduction 95 Pause avant l’accès par tous • Rien de nouveau, sauf cette interface package cnam.android; interface SMSServiceI{ void start(); void stop(); long received(); } – Architecture classique • Un service • Une liaison à l’aide d’une instance de la classe ServiceConnection Android_Introduction 96 Le manifest, installation du service Pour tous, et ici dans un processus séparé <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="seja.android" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".ServiceSMSReceivedActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".SMSService" android:exported="true" android:process="seja.android.SMSService" /> </application> </manifest> Android_Introduction 97 Un autre client depuis une autre application • Recopie du fichier .aidl, (langage commun) – Noms de paquetage identiques • Même séquence qu’un client du même contexte – Recherche du service – Connexion au service Android_Introduction 98 Un client ordinaire d’une autre application public void onClickHow(View v){ if(!connecte){ Intent intent = new Intent(); intent.setClassName("seja.android", "seja.android.SMSService"); this.connexion = new ConnexionAuServiceSMS(); try{ bindService( intent, connexion, Context.BIND_AUTO_CREATE); }catch(Exception e){} connecte = true; }else{ try { texte.setText(Long.toString(service.received())); } catch (Exception e) {} }} private class ConnexionAuServiceSMS implements ServiceConnection{ à l’identique d’un client présent dans la même application Android_Introduction 99 Exemple2 : SMSService enrichi • Un compteur de SMS reçus – A chaque sms reçu un compteur est incrémenté – Service accessible par toute application • Le service a maintenant l’intention de recevoir des SMS – IntentFilter filter = new IntentFilter(SMS_RECEIVED); – registerReceiver(new SMSReceiver(), filter); • Un client recherchera ce service via le middleware • Le service : SMSService Android_Introduction 100 ContentProvider • Sauvegarde et restitution de données – Données accessibles à toutes applications • ContentProvider – Persistance – DAO/CRUD • Data Access Object • Create Retrieve Update et Delete Android_Introduction 101 Mes Contacts, un client le ContentProvider prédéfini : phone Android_Introduction 102 ContentProvider • ContentProvider, comme les contacts, accès – ContentResolver resolver = getContentResolver(); Identification du bon « Contentprovider » grâce à son URI – Uri uri = android.provider.Contacts.Phones.CONTENT_URI; – String s = uri.toString(); – // assert s.equals("content://contacts/phone"); – Appel de resolver.query • Pour une interrogation – Parcours à l’aide d’un « Cursor » Android_Introduction 103 Cursor comme ResultSet Android_Introduction 104 Conclusion • Ce n’est qu’une introduction … – Approche par les patrons s’impose pour la partie Service et ContentProvider … Android_Introduction 105