vous présente :Spécialiste Android Java J2EE        Auteur du livredisponible sur                                   1
Formateur Consultant Expert Android                                           mathias.seguy.it@gmail.com (mail)           ...
• Pourquoi de l’architecture ?• Architecture d’applications Stand Alone (Swing)• Android Application Design• Android ProTi...
4
Ex: Lactivité utilise un service Rest pour mettre à jour des informations de manière cyclique.                      Thread...
6
Le modèle N-Tiers et ses dépendances.Chaque couche possède une interface.Chaque couche possède un cahier des charges très ...
Les fondations de l’application.La couche transverse est connue de tous mais ne connait personne. Objet      Service Utili...
Le cerveau de l’application.La couche service contient les services métiers.                  LoginSrv                    ...
La mémoire de l’application.                                                     La couche DAO : Data Access Object.Elle n...
La bouche et les oreilles de l’application.La couche COM (communication) prend en charge l’accès aux données et services d...
Hiérarchie des packages de vues.La couche IHM contient l’ensemble des écrans et se scinde en plusieurs sous-packages.Une a...
Le modèle Model – (Vue Controller).Le deuxième concept fort est la séparation entre l’affichage des objets et leur gestion...
14
Houston, we’ve got a problem.Avec Android le problème est « Comment mettre en place ce Design en respect du cycle de vie d...
Les contraintes sont:Il faut que notre Design réussisse quatre challenges:•On ne doit instancier un élément qu’à la demand...
L’enfer de la fragmentation                                   Notre Design doit être capable de :• Lancer l’application en...
Le Pattern Parrallel Activity étendu :Instancier l’implémentation d’un service / dune brique applicative en fonction de la...
19
Parrallel Activity Pattern and fragments :Les activités sont devenues des coquilles vides qui écoutent les Intents, impose...
Les fragment et les support.v4.app.Fragment ne sont pas compatibles:                                          Ils ne possè...
Les fragments (post-HC et pre-HC) partagent le même modèle.Les fragments sont purement du code dupliqué. Les modèles sont ...
Le modèle MVC Android.Le modèle MVC Android se décline en trois types :                                                   ...
Votre package UI doit alors ressembler à                         Attention à la duplication du code                       ...
25
Base class for those who need to maintain global application state.La classe application va nous permettre de répondre aux...
Application, où es-tu?                                   Utilisez le pattern du singleton.public class DesignApplication e...
Les services métiers doivent :                                                              finir leur traitement,        ...
Les services Android sont les services métiers de lapplication.                                                           ...
Le ServiceLoaderLe service Loader a pour objectif :•de lancer les services de lapplication,•de se lier à eux en mode bind ...
Le serviceLoader : Mise en place du LazyLoadingprivate void launchServiceAsync() {                       Activity         ...
Persister les services : lobjet Application instancie le ServiceLoader                                   Persitence des se...
Communication                                                                                                             ...
Objectif pour le développeur final : peu de code.public abstract class MyActivity extends MActivity {...                  ...
Lactivité mèrepublic abstract class MActivity extends Activity {                                            1) Mise en pla...
Le service mère       1) Mise en place du Binding automatique des services avec le          service locatorpublic class MS...
Les services filles1) Déclare les identifiants de méthode du service2) Mets en place les méthodes du services3) Et renvoie...
Le ServiceHelper1) Construit et envoie les Intents dans le système pour être automatiquement récupérés par les activités a...
ServiceHelper et ServiceLoader full pattern                                                                               ...
Le projet MythicServiceHelper imlplémente ce pattern (version alpha draft)                      Tout le code est disponibl...
Les services métiers sont des services Android.                           Application                                   Se...
La couche BroadCast est une couche à part entière                       BroadCast                        Receiver         ...
Où se trouve le ContentProvider ?La couche DAO pose le problème de « où mettre les ContentProvider ? ».Pour rappel:  “You ...
Pas de changement avec larchitecture n-tiers usuelle dapplications stand-alones.                                     NDK. ...
J’attire votre attention sur la nécessité de mettre en place un gestionnaire d’exception qui vous permettent de les logger...
BroadCast                          Receiver                                                              Net              ...
La solution au problème des Threads de traitements.                       Thread I.H.M                                 Thr...
48
From Google I/O And DevoxxCe chapitre est un extrait des « meilleurs » proTips donnés par les équipes Google lors des Goog...
Use ViewStub  La ViewStub permet le lazy loading de layouts.   <ViewStub   android:id="@+id/stub_import"   android:inflate...
Use merge et include                                                                                            Without me...
ListView and ArrayAdpater : Use ViewHolder and convertView   public View getView(int position, View convertView, ViewGroup...
Know your Network and Battery context                                      <receiver android:name="DeviceStateReceiever" >...
KeyBoard and EditText : Customize KeyBoard and set Action  Quand vous définissez un champ de type EditText vous devez défi...
Always be asynchronous                                           Rendez tout asynchrone en utilisant:                     ...
Use the big cookies strategy when possible  Préférez transférer un gros paquet de données au travers d’internet quand c’es...
57
From Google I/O 2012Ce chapitre est un extrait de la conférence des Google I/O 2012 :•Multiversioning Android, Bruno Olive...
Be Lazy  Utiliser une classe abstraite qui sera instanciée par une factory et renverra l’implémentation correspondant à le...
Resources are your best friend, use them.  Utilisez des booléens pour savoir quelle est la version du système. Ils s’utili...
Hériter du thème de la version.  Restez cohérent avec le thème du SDK de l’appareil cible, conservez une application cohér...
Utiliser les Fragments et l’ActionBar sur toutes vos versions.  Ayez une application identique quelque soit la version du ...
Utiliser les notifications PreJB, PostJB.  Utilisez les notifications sur toutes les versions avec le NotificationCompat.B...
L’ordre des boutons a changé depuis ICS.  Avant ICS le bouton OK est à gauche, le bouton non ou cancel à droite.  Après IC...
Min, max et target SDK importe.  Définissez toujours votre targetSdk comme le plus haut possible pour profiter des nouveau...
66
Ne pas oublier le projet de Tests.L’architecte a à charge la conception de l’application mais aussi la conception de l’app...
Ces outils sont :    • Le SDK de Test fourni par Android,    • JUnit 3 (intégré au SDK d’Android),    • Maven pour constru...
Communauté Google+ Android projects on Github                     Github open source projectshttps://plus.google.com/u/0/c...
Cette conférence utilise les références suivantes :Les EBooks et tutoriels d’Android2ee : http://www.android2ee.comLes sit...
Merci pour votre attention.                                       android2ee.com.                                         ...
Prochain SlideShare
Chargement dans…5
×

Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur d'Android2EE spécialiste de la formation Android.

4 605 vues

Publié le

La conférence « Architecture Android » de Mathias Seguy (Android2EE).
Si l’architecture d’applications Android vous questionne, vous intéresse, vous mystifie cette conférence est faîte pour vous.
Elle s’attachera à décrire les design patterns, contraintes et bonnes pratiques Android. Cela nous permettra de concevoir une architecture propre aux applications Android.
La conférence se conclura en donner les pro-tips Android provenant des GoogleIO et Devoxx qu’il faut connaitre pour concevoir des applications pertinentes sous Android.

Cette conférence a eu lieu le mardi 19 Mars 2013, à 19h.
Si vous êtes un JUG ou un AUG et que cette conférence vous interesse, n'hésitez pas à me contacter.

Si vous souhaitez apprendre la technologie Android, contacter moi: mathias.seguy@android2ee.com, je suis formateur Android et les formations Android que je dispense sont exceptionnelles.

Speaker:Mathias est le fondateur de la société Android2ee spécialisée dans la technologie Android.
Il est :
• formateur Android,
• expert logiciel Android,
• speaker Android sur de grandes conférences Java : Devoxx France, Eclipse Day Toulouse, JCertif Africa, Toulouse JUG, CocoAhead,…
• Rédacteur Android sur Developpez.com ;
• Programmateur Android : MyLight, MyTorch, MySensors, JCertifMobile disponibles sur GooglePlay ;
• Docteur en Mathématiques Fondamentales et Ingénieur de l’ENSEEIHT ;
• Expert technique de l’agence nationale de la recherche française ;
Il présentera au cours de cette conférence sa vision sur la mise en place d’une architecture d’une application Android pertinente et partagera les meilleurs pro-tips (astuces de pro) de sa connaissance. A ne pas manquez.

Mathias Séguy
mathias.seguy@android2ee.com
Fondateur Android2EE
Formation – Expertise – Consulting Android.
Ebooks pour apprendre la programmation sous Android.

Publié dans : Technologie
1 commentaire
5 j’aime
Statistiques
Remarques
  • Conférence 'Architecture Android' du 19 Mars 2013 par Mathias Seguy fondateur d'Android2EE spécialiste de la formation Android. from Mathias Seguy
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
Aucun téléchargement
Vues
Nombre de vues
4 605
Sur SlideShare
0
Issues des intégrations
0
Intégrations
189
Actions
Partages
0
Téléchargements
9
Commentaires
1
J’aime
5
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Conférence "Architecture Android" du 19 Mars 2013 par Mathias Seguy fondateur d'Android2EE spécialiste de la formation Android.

  1. 1. vous présente :Spécialiste Android Java J2EE Auteur du livredisponible sur 1
  2. 2. Formateur Consultant Expert Android mathias.seguy.it@gmail.com (mail) @android2ee (twitter) Fondateur Android2EE – Formation Expertise Android Auteur d’EBooks sur la programmation Android (Android2ee.com) Docteur en Mathématiques Fondamentales Expert Technique de lAgence Nationale de la Recherche Rédacteur sur Developpez.com Blogs Android : Android2EE sur DVP et Android2ee sur BlogSpotDoctorat Mathématiques Fondamentales Via CapGemini Via Sopra Naissance Android2EE Siemens Magnus DGA CNES Airbus Airbus Airbus STI Android2EE VDO 03 04 05 06 07 08 09 10 11 12 Java J2EE Android Manager Manager Leader Leader Leader Leader Directeur Fondateur Développeur Développeur IHM Technique Technique Manager Technique Technique Android2EEMaster Informatique de Chez STI l’ENSEEIHT 2
  3. 3. • Pourquoi de l’architecture ?• Architecture d’applications Stand Alone (Swing)• Android Application Design• Android ProTips• MutliVersionning & Resources are yourbest friends• Automatiser les tests ! 3
  4. 4. 4
  5. 5. Ex: Lactivité utilise un service Rest pour mettre à jour des informations de manière cyclique. Thread I.H.M Thread de traitement Activity Handler sendMessage() REST Call message OnDestroy() OnCreate() Thread de traitement initiale Thread I.H.M sendMessage() REST Call Activity Handler fantôme fantôme Thread de traitement Activity Handler sendMessage() REST Call message 5
  6. 6. 6
  7. 7. Le modèle N-Tiers et ses dépendances.Chaque couche possède une interface.Chaque couche possède un cahier des charges très précis.Les dépendances entres les packages sont extrêmement importantes. Internet Façade COM COM Façade DataBase IHM Service Service Façade DAO DAO FileSystemUse or not Transverse Use 7
  8. 8. Les fondations de l’application.La couche transverse est connue de tous mais ne connait personne. Objet Service Utilitaire Transverse Service des Exceptions métiers PojoA Log HttpUtil ExceptionManager PojoB Tracker DateUtil ExceptionManaged DtoA StringUtil 8
  9. 9. Le cerveau de l’application.La couche service contient les services métiers. LoginSrv SimulationSrv MainStreamSrv MainStreamSrvIntf SimulationSrvIntf LoginSrvIntf LoginSrvImpl MainStreamSrvImpl SimulationSrvImpl LoginUtil MSDisplaySrv LoginCore MsUpdateSrv 9
  10. 10. La mémoire de l’application. La couche DAO : Data Access Object.Elle n’expose ses services qu’au travers d’interfaces.Utiliser les factory.Expose les méthodes CRUD (Create, Read, Update, Delete) et autres méthodes spécifiques. Human SqlUtil HumanDaoFactory SqlUtil HumanDaoIntf HumanDaoHb8 HumanDaoJdbc HumanDaoFS 10
  11. 11. La bouche et les oreilles de l’application.La couche COM (communication) prend en charge l’accès aux données et services déportés sur un serveur (web ou autre).On ne doit pas spécifier le type de communication mais le service rendu. ForecastCom HttpComUtil ForecastComIntf use HttpComUtilIntf ForecastComImpl HttpComUtilImpl 11
  12. 12. Hiérarchie des packages de vues.La couche IHM contient l’ensemble des écrans et se scinde en plusieurs sous-packages.Une application hiérarchise ses vues, cette hiérarchie doit se retrouver dans vos packages. Cohérence 12
  13. 13. Le modèle Model – (Vue Controller).Le deuxième concept fort est la séparation entre l’affichage des objets et leur gestion. La view affiche le model gère les données.Le model se charge de la gestion des objets affichés et la communication avec les services. 1 1 FamilyView FamilyModel FamilySrvIntf 0 0 use n n 1 1 HumanView HumanModel HumanSrvIntf 0 0 n n use 1 1 AdressView AdressModel AdressSrvIntf 13
  14. 14. 14
  15. 15. Houston, we’ve got a problem.Avec Android le problème est « Comment mettre en place ce Design en respect du cycle de vie des activités? ». Certaines application Swing ont un temps de boot de 30 secondes, et ce n’est pas possible sur Android. 15
  16. 16. Les contraintes sont:Il faut que notre Design réussisse quatre challenges:•On ne doit instancier un élément qu’à la demande;•Quand un élément est instancié, il faut qu’il le reste;•On ne doit pas détruire les éléments instanciés quand l’activité estdéconstruite pour être immédiatement reconstruite;•On doit pouvoir laisser les traitements se terminer (au sens use case) tout enétant capable de leur signaler que l’application est terminée... 16
  17. 17. L’enfer de la fragmentation Notre Design doit être capable de :• Lancer l’application en mode Post-HoneyComb/ICS/JB ou en mode pre HoneyComb / ICS / JB,•Instancier des composants en fonction de la version du système 17
  18. 18. Le Pattern Parrallel Activity étendu :Instancier l’implémentation d’un service / dune brique applicative en fonction de laversion du système. Human AServiceFactory AServiceIntf AServiceV6Impl AServiceV11Imp AServiceV13Imp 18
  19. 19. 19
  20. 20. Parrallel Activity Pattern and fragments :Les activités sont devenues des coquilles vides qui écoutent les Intents, imposent le cycle de vie et re-routent les évènements vers lesfragments qui les composent. C’est la nouvelle philosophie générale.Votre application lancera une première activité qui aura comme unique objectif de lancer soit l’activité dans son mode pré-HoneyComb soitdans son mode post HC. Ces deux activités utiliseront les mêmes classes de type Fragment (grâce à la support-librairy). Il faut décliner chaque Intent en post et pré HC. ActivityLegacy 0 1 LauncherActivity Fragment 1 ActivityHC 0 20
  21. 21. Les fragment et les support.v4.app.Fragment ne sont pas compatibles: Ils ne possèdent pas d’interface commune. Duplication du code de vos fragments (seules différences leurs imports). 0 1 ActivityLegacy FragmentLegLauncherActivity 0 1 ActivityHC FragmentHC 21
  22. 22. Les fragments (post-HC et pre-HC) partagent le même modèle.Les fragments sont purement du code dupliqué. Les modèles sont indépendants de la version du système.Chaque Fragment est associé à son modèle. Chaque activité se décline en deux types : pré et post HC. 0 1 ActivityLegacy FragmentLegacy 1 1 use LauncherActivity FragmentModel AServiceSrvIntf 1 0 1 1 ActivityHC FragmentHC 22
  23. 23. Le modèle MVC Android.Le modèle MVC Android se décline en trois types : 0 1None : Les données à afficher sont en read-only, peu de traitement au ActivityLegacy FragmentLegacyniveau des données. LauncherActivity 0 1 ActivityHC FragmentHCSimple : Chaque fragment gère ses données au moyen de son modèle.Full : L’activité et les fragments ont des données corrélées qu’il fautsynchroniser au niveau des modèles. 0 1 0 1 ActivityLegacy FragmentLegacy ActivityLegacy FragmentLegacy 1 1 1 use ParentIntf 1 1 LauncherActivity 1 FragmentModel LauncherActivity FragmentModel 1 ActivityModel 1 1 0 1 1 1 1 0 1 ActivityHC FragmentHC ActivityHC FragmentHC 23
  24. 24. Votre package UI doit alors ressembler à Attention à la duplication du code quelque chose comme le schéma ci-contre: Les activités/fragments Legacy, HC, ICS, JB possèdent le même modèle.Il reste les problématiques :•de la démultiplication des activités qui est plus fatigante en termes : • de code, •de maintenabilité•et la duplication de code des fragments. 24
  25. 25. 25
  26. 26. Base class for those who need to maintain global application state.La classe application va nous permettre de répondre aux problématiques suivantes : instancier un élément qu’à la demande; un élément est instancié doit le rester; On ne doit pas détruire les éléments instanciés ne doivent pas être détruit quand l’activité est déconstruite/reconstruite; On doit pouvoir laisser les traitements se terminer L’objet application est créé dès que l’un des composants de votre application est instanciée et est détruite quand le dernier composant est détruit. public class DesignApplication extends Application { Déclaration dans le AndroidManifest.xml HumanDaoIntf humanDao; /** * @return the humanDao */ <application public final synchronized HumanDaoIntf getHumanDao() { android:icon="@drawable/ic_launcher" if(humanDao==null) { android:label="@string/app_name" android:name=".MyApplication"> humanDao=new HumanDaoCPImpl(); } return humanDao; } } 26
  27. 27. Application, où es-tu? Utilisez le pattern du singleton.public class DesignApplication extends Déclaration dans le AndroidManifest.xmlApplication {@Override <applicationpublic void onCreate() { android:icon="@drawable/ic_launcher"super.onCreate(); android:label="@string/app_name" android:name=".MyApplication">//First record the Application objectAppSingleton.INSTANCE.setApp(this);…} Le code pour récupérer l’Application quand vous êtes ni dans une Activity ni dans un service :public enum AppSingleton { //Retrouver l’applicationINSTANCE; AppSingleton.INSTANCE.getApp();private DesignApplication application;/** * @return */public DesignApplication getApp() {return application; Le code pour récupérer l’Application quand vous êtes dans} une Activity ou dans un service :/** * @param app */ //Retrieve the applicationpublic void setApp(Application app) { (DesignApplication )getApplication();application=app;}} 27
  28. 28. Les services métiers doivent : finir leur traitement, être instancié à la demande, persister leur instanciation, ne pas suivre le cycle de vie de lactivité mais celui de lapplication.Pour résoudre ce problème vous avez deux choix : •Soit votre service métier est un service Android. •Soit ce n’est pas un service Android et il faut le faire à la main.Le second cas est complexe est n’est pas recommandé. 28
  29. 29. Les services Android sont les services métiers de lapplication. Net Façade COM COM Service Couche Façade DB Métier IHM Service Android Façade DAO DAO FSUse or not Transverse Use 29
  30. 30. Le ServiceLoaderLe service Loader a pour objectif :•de lancer les services de lapplication,•de se lier à eux en mode bind (et ainsi conserver un pointeur vers eux),•de se délier à eux quand lapplication sarrête (et ainsi de les arreter). LazyLoading Pour cela, DaughterService2 1-1 •Cest un singleton (une énumération) ServiceLoader DaughterService1 •Il connait ses services via une 1-1 liste de ServiceConnection ServiceLoader •Possède une méthode darrêt. Caption BIND 1 LazyLoading Et il faut lécrire à la main. WorkFlow getService Nappartient pas au SDK. MService 2 callBack Contains Extends DaughterActivity service.doSomething() 3 30
  31. 31. Le serviceLoader : Mise en place du LazyLoadingprivate void launchServiceAsync() { Activity /** * The method to be called by the activities ServiceLoader// load your service... @return the dService (could be null if not started yet) */ServiceLoader.instance.getdService(new OnServiceCallBack() { public void getdService(OnServiceCallBack onServiceCallBack) { public void onServiceCallBack(MService service) { startDummySrv(); // insure the service is started // so just call the method you want of your service // then if the service is null add the callBack to the list of elements waiting for the service ((DummyService) service).doSomethingAsynch(getActivityId()); to be instantiated }});} if (dService == null) {// add to the callback list onDServiceCallBack.add(onServiceCallBack);/** * The service you want to expose to activities */ ServiceLoader } else {// else, service is not null, just use directly the callbackprivate DummyService dService = null; onServiceCallBack.onServiceCallBack(dService);/** * The list of the callback of the service instantiation */ }}private List<OnServiceCallBack> onDServiceCallBack;/** * Method to start the DummyService service */ /** * The object to handle the connection of this with the service. So this will keep a pointer onprivate void startDummySrv() {// insure the list is not null the service not loosing it in the memory. */ ServiceLoader if (onDServiceCallBack == null) {onDServiceCallBack = new private ServiceConnection dummySrvConn = new ServiceConnection() { ArrayList<OnServiceCallBack>();} // as usual deconnexion // if the service is null, launch it using the Bind process @Override if (dService == null) { public void onServiceDisconnected(ComponentName name) {dService = null;} Intent service = new // as usual connection Intent(MAppInstance.ins.getApplication(), DummyService.class) @Override ; public void onServiceConnected(ComponentName name, IBinder service) { MAppInstance.ins.getApplication().bindService(service, dummySrv // use the IBinder Conn,Service.START_STICKY);} dService = (DummyService) ((MService.LocalBinder) service).getService(); // add it to the list of bound services (if not in yet): // notify callback the service is awake if(!boundServices.contains(dummySrvConn)) for (OnServiceCallBack callBack : onDServiceCallBack) { {boundServices.add(dummySrvConn);} callBack.onServiceCallBack(dService);} }// and clear the callback list onDServiceCallBack.clear(); onDServiceCallBack = null;}}; 31
  32. 32. Persister les services : lobjet Application instancie le ServiceLoader Persitence des services public class MApplication extends Application { DaughterService2 /** * Just keep a reference on it to Persistence 1-1 avoid unusefull 1-0 destruction/recreation of services */ Caption Application ServiceLoader DaughterService1 private ServiceLoader sLoader; 1-1 @Override public void onCreate() {WorkFlow BIND ... 1 LazyLoading // keep the ref getService sLoader =Contains MService 2 ServiceLoader.instance; callBack }Extends /** * This method has to be called when DaughterActivity the application died. It kill all the service.doSomething() services So find the activity that quit 3 the application and add that method */ public void onBackPressed() { // Call the application object and release the services sLoader.unbindAndDie(); } } 32
  33. 33. Communication Service-Activity 1 DaughterActivity DaughterService1 service.doSomething(String ActivityId) 4 onServiceCallBack 2(int serviceMethodId, MActivity callBack(methodID, activityID, result); Object result) 3 1-1 Build And Launch Intent to the Activity using its ActivityId BroadCastReceiver ServiceHelper Caption WorkFlow Contains Extends 33
  34. 34. Objectif pour le développeur final : peu de code.public abstract class MyActivity extends MActivity {... Activity /** Retrieving results from business services calls *******/ Activityprivate void launchServiceAsync() { /** The method to implement to root your service call with the method that handle// find your service...(lazy loading part) the return. Its called back via intent through MActivity. So you just need to checkServiceLoader.instance.getdService(new OnServiceCallBack() { your method id and do something with your result */public void onServiceCallBack(MService service) { 4 protected void onServiceCallBack(int serviceMethodId, Object result) {// so just call the method you want of your service((DummyService) service).doSomethingAsynch(getActivityId());}});} 1 switch (serviceMethodId) { case DummyService.doSomethingID:public class DummyService extends MService { // call your result method doSomethingResult(result) Service onServiceResult((ConstantData) result); 5/** * The id of the method doSomething break; Activity * It has to be unique for your whole application and for each servicemethod default:of it. break;} */ }public static final int doSomethingID = 10000101; private void onServiceResult(ConstantData message) { 6/** * A dummy method with the return sent to the calling activity // You can also display a indeterminate progress bar * * @param activityId The unique id of the calling activity */ simpleServiceCall--;public void doSomething(String activityId) { 2 if(simpleServiceCall==0) {// do your treatment prbResultSimple.setVisibility(View.GONE);}ConstantData data = new ConstantData("SomeResuls", 11021974, true); txvResultSimple.setText(message.message);}// And the important part is here// When your treatment is over, just use the serviceHelper to contact the callingActivity and to send the method return to that activityServiceHelper.instance.callBack(doSomethingID, activityId, data); 3} 34
  35. 35. Lactivité mèrepublic abstract class MActivity extends Activity { 1) Mise en place de lécoute transparente des Intents via une/** * @return a unique identifier of the activity to be attached to intents that have to be activité mère.calledBack by the activity */ 2) Enregistrement en tant quécouteur dintents qui ont pourpublic String getActivityId() {// so use the canonical name it should be enough action le getActivityIdreturn getClass().getCanonicalName();} 3) Parcing du retour dans le BroadcastReceiver et appel deprotected abstract void onServiceCallBack(int serviceMethodId, Object result); la méthode onServiceCallBackprivate BroadcastReceiver serviceCallBackReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d("MActivity", "serviceCallBackReceiver:onReceive, called: " + intent.getAction());// first be sure to listen for the right intentif (intent.getAction() == getActivityId()) {// retrieve the type of the result objectString resType = intent.getStringExtra(ServiceHelper.SRV_MTH_RES_TYPE);// using that type, retrieve the result object// there will be a lot of case, should be the same case than the number of @Override// intent.get**Extra method protected void onResume() {if (resType.equals(ServiceHelper.Parcelable)) { super.onResume(); onServiceCallBack(intent.getIntExtra(ServiceHelper.SRV_MTH_ID, -1), registerReceiver(serviceCallBackReceiver, new IntentFilter(getActivityId()));} intent.getParcelableExtra(ServiceHelper.SRV_MTH_RES)); @Override} else if (resType.equals(ServiceHelper.String)) { protected void onPause() {// other case super.onPause(); onServiceCallBack(intent.getIntExtra(ServiceHelper.SRV_MTH_ID, -1), unregisterReceiver(serviceCallBackReceiver);} intent.getStringExtra(ServiceHelper.SRV_MTH_RES)); }}// and so on}}}; 35
  36. 36. Le service mère 1) Mise en place du Binding automatique des services avec le service locatorpublic class MService extends Service {/** The binder process ***********//** * The Binder */private final Binder binder = new LocalBinder();/** *This class aims to be a local Binder that keep and share a pointer on the instance of this*/public class LocalBinder extends Binder { // as usual public MService getService() {// return the instance of the service return MService.this;} }@Overridepublic IBinder onBind(Intent intent) { return binder;}@Overridepublic void onDestroy() { super.onDestroy();}} 36
  37. 37. Les services filles1) Déclare les identifiants de méthode du service2) Mets en place les méthodes du services3) Et renvoie toujours le résultat via: ServiceHelper.instance.callBack(doSomethingID, activityId, data); public class DummyService extends MService { /** * The id of the method doSomething * It has to be unique for your whole application and for each servicemethod of it. */ public static final int doSomethingID = 10000101; /** * A dummy method with the return sent to the calling activity * * @param activityId The unique id of the calling activity */ public void doSomething(String activityId) { // do your treatment ConstantData data = new ConstantData("SomeResuls", 11021974, true); // And the important part is here // When your treatment is over, just use the serviceHelper to contact the calling Activity // and to send the method return to that activity ServiceHelper.instance.callBack(doSomethingID, activityId, data); } 37
  38. 38. Le ServiceHelper1) Construit et envoie les Intents dans le système pour être automatiquement récupérés par les activités appelantes.public enum ServiceHelper { /** CallBack ******/instance; /** * This method just create an Intent and launched it/** Constants ***/ * @param serviceMethodId : The method that ask for sending the result to the activity/** The constant to be used by intent to carry the services methods * @param activityId : The activity that calls the method, the intent will be received by itid */ * @param result: The object to carry (the result object of the method) */public static final String SRV_MTH_ID = public void callBack(int serviceMethodId, String activityId, Object result) {"com.android2ee.service.method.id"; //create the Intent/** * The constant to be used by intent to carry the services Intent callBack = new Intent(activityId);methods result */ //add the service method idpublic static final String SRV_MTH_RES = callBack.putExtra(SRV_MTH_ID, serviceMethodId);"com.android2ee.service.method.result"; //your object should implements Parcelable/** * The constant to be used by intent to carry the services //add the type of the result object (to unparse)methods result */ if (result instanceof Parcelable) {public static final String SRV_MTH_RES_TYPE = callBack.putExtra(SRV_MTH_RES, (Parcelable) result);com.android2ee.service.method.result.type"; callBack.putExtra(SRV_MTH_RES_TYPE,Parcelable); }else if( result instanceof String) { callBack.putExtra(SRV_MTH_RES, (String) result); callBack.putExtra(SRV_MTH_RES_TYPE,String); }//and so on //Then send the Intent MAppInstance.ins.get().sendBroadcast(callBack); } } 38
  39. 39. ServiceHelper et ServiceLoader full pattern DaughterService2 Persistence 1-1 Caption 1-0 Application ServiceLoader DaughterService1 1-1WorkFlow BIND 1Contains LazyLoading getService MService 2Extends callBack Communication DaughterActivity Service-Activity 6 service.doSomething() onServiceCallBack 3 4 (int serviceMethodId, MActivity callBack(methodID, activityID, result); Object result) 5 1-1 Build And Launch Intent to the Activity using its ActivityId BroadCastReceiver ServiceHelper 39
  40. 40. Le projet MythicServiceHelper imlplémente ce pattern (version alpha draft) Tout le code est disponible : https://github.com/MathiasSeguy-Android2EE/MythicServiceHelper 40
  41. 41. Les services métiers sont des services Android. Application Service Net Façade Métier COM COM Android Couche IHM Façade Service ServiceLoader DB MActivity ServiceHelper Façade start DAO MService DAO FS Use or not Transverse Use Préserver les interfacesIl est important de pouvoir changer la manière dont fonctionne un service sans avoir à modifier le reste de l‘application. Il doit pouvoirconserver son interface tout en changeant son implémentation sans pour autant impacter le reste de l’application. 41
  42. 42. La couche BroadCast est une couche à part entière BroadCast Receiver Net Façade COM COM Service DB Couche Façade Métier IHM Service Android start Façade DAO DAO FSUse or not Transverse Use 42
  43. 43. Où se trouve le ContentProvider ?La couche DAO pose le problème de « où mettre les ContentProvider ? ».Pour rappel: “You dont need to develop your own provider if you dont intend to share your data with other applications. However, you do need your own provider to provide custom search suggestions in your own application. You also need your own provider if you want to copy and paste complex data or files from your application to other applications.” dixit developer.android.com les ContentProviders sont vos DAO publiquesAinsi vos DAO contiennent bien vos ContentProvider et le Design est celui-ci : Cela ne veut pas dire que toutes vos DAO doivent posséder un ContentProvider, mais que si elles en contiennent un elles le mettent à la Human même hauteur que son interface. En effet, il n’y a qu’une implémentation pour un ContentProvider. HumanContentProvider HumanDBOpenHelper HumanDaoIntf HumanDaoSQLite Se posera à vous la question de la redondance des méthodes. Pour cela vous pouvez re-router les méthodes de votre ContentProvider vers votre HumanDaoOrlite HumanDaoFactory interface de DAO, ce qui est le plus propre. HumanDaoFS 43
  44. 44. Pas de changement avec larchitecture n-tiers usuelle dapplications stand-alones. NDK. 44
  45. 45. J’attire votre attention sur la nécessité de mettre en place un gestionnaire d’exception qui vous permettent de les logger/persister enbase/afficher à l’utilisateur. Service des Exceptions ExceptionManager ExceptionManaged 45
  46. 46. BroadCast Receiver Net Application Façade COM COM Couche Service Métier Android IHM ServiceLoader DB Façade Service MActivity ServiceHelper start Façade DAO MService DAO FSUse or not Transverse Use 46
  47. 47. La solution au problème des Threads de traitements. Thread I.H.M Thread de traitement ServiceOnDestroy() sendMessage() REST CallOnCreate() Handler BIND message Activity 47
  48. 48. 48
  49. 49. From Google I/O And DevoxxCe chapitre est un extrait des « meilleurs » proTips donnés par les équipes Google lors des GoogleI/O, notamment :•Android ProTips, Reto Meier, Google I/O 2011•Making Good Apps Great , Reto Meier, Google I/O 2012•Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010Merci à eux pour ces présentations. 49
  50. 50. Use ViewStub La ViewStub permet le lazy loading de layouts. <ViewStub android:id="@+id/stub_import" android:inflatedId="@+id/panel_import" android:layout="@layout/progress_overlay" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" /> id/panel_import findViewById(R.id.stub_import).setVisibility(View.VISIBLE); // or View importPanel = ((ViewStub) id/stub_import findViewById(R.id.stub_import)).inflate();From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010 50
  51. 51. Use merge et include Without merge With merge Le merge permet d’inclure les layouts les uns dans les autres sans redondance. Cela permet aussi la décomposition et la réutilisation des layout. <!-- The merge tag must be the root tag --> <merge xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Content --> </merge> <!– The include tag is the one to use--> <LinearLayout …> <include layout="@layout/subLayout" /> <LinearLayout> .. </LinearLayout> </LinearLayout>From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010 51
  52. 52. ListView and ArrayAdpater : Use ViewHolder and convertView public View getView(int position, View convertView, ViewGroup parent) { static class ViewHolder { ViewHolder holder; TextView text; if (convertView == null) { ImageView icon; convertView = mInflater.inflate(R.layout.list_item_icon_text, parent, false); } holder = new ViewHolder(); holder.text = (TextView) convertView.findViewById(R.id.text); holder.icon = (ImageView) convertView.findViewById(R.id.icon); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text.setText(DATA[position]); holder.icon.setImageBitmap((position & 1) ==? mIcon1 : mIcon2); return convertView; }From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010 52
  53. 53. Know your Network and Battery context <receiver android:name="DeviceStateReceiever" > <action android:name="android.intent.action.ACTION_DOCK_EVENT" /> <action android:name="android.intent.action.ACTION_BATTERY_LOW" /> <action android:name="android.intent.action.ACTION_POWER_CONNECTED" /> <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.net.wifi.STATE_CHANGE" /> </receiver> ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean isConnected = activeNetwork.isConnectedOrConnecting(); boolean isMobile = activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE;Android ProTips, Reto Meier, Google I/O 2011 53
  54. 54. KeyBoard and EditText : Customize KeyBoard and set Action Quand vous définissez un champ de type EditText vous devez définir : • Son type de clavier • L’action IME • (et le Hint) <EditText EditText.OnEditorActionListener myActionListener = new android:id="@+id/editEmailInput" EditText.OnEditorActionListener() { android:layout_width="match_parent" @Override android:layout_height="wrap_content" public boolean onEditorAction(EditText v, int actionId, KeyEvent event) { android:hint="@string/compose_email_hint" if (actionId == EditorInfo.IME_ACTION_DONE) { android:imeOptions="actionSend|flagNoEnterAction" // do here your stuff f android:inputType="textShortMessage| return true; textAutoCorrect| } textCapSentences" /> return false; } };Android ProTips, Reto Meier, Google I/O 2011 54
  55. 55. Always be asynchronous Rendez tout asynchrone en utilisant: •le ServiceHelper; •les Handler, Asynctask; •IntentService (le système des Intents quoi); •AsyncQueryHandler (le GetContentResolver en un sens); •Loader (abstractClass) and CursorLoader (HoneyComb only).Android ProTips, Reto Meier, Google I/O 2011 55
  56. 56. Use the big cookies strategy when possible Préférez transférer un gros paquet de données au travers d’internet quand c’est possible plutôt que plein de petits paquets. int prefetchCacheSize = DEFAULT_PREFETCH_CACHE; switch (activeNetwork.getType()) { case ConnectivityManager.TYPE_WIFI: prefetchCacheSize = MAX_PREFETCH_CACHE; break; case ConnectivityManager.TYPE_MOBILE): { switch (telephonyManager.getNetworkType()) { case TelephonyManager.NETWORK_TYPE_LTE: case TelephonyManager.NETWORK_TYPE_HSPAP: prefetchCacheSize *= 4; break; case TelephonyManager.NETWORK_TYPE_EDGE: case TelephonyManager.NETWORK_TYPE_GPRS: prefetchCacheSize /= 2; break; default: break; } break; } default: break; }Making Good Apps Great, Reto Meier, Google I/O 2012 56
  57. 57. 57
  58. 58. From Google I/O 2012Ce chapitre est un extrait de la conférence des Google I/O 2012 :•Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012Qui est exceptionnel sur la lutte contre la fragmentation, un très grand moment, merci à eux. 58
  59. 59. Be Lazy Utiliser une classe abstraite qui sera instanciée par une factory et renverra l’implémentation correspondant à le version du système. Activity public abstract class VersionedLoremIpsum { VersionedLoremIpsum li; public abstract String doLorem(); li=VLIFactory.get() public abstract int doIpsum(); } public class EclairLoremIpsum public class FroyoLoremIpsum VLIFactory extends VersionedLoremIpsum { extends EclairLoremIpsum { public static VersionedLoremIpsum get( public String doLorem() { public String doLorem() { int sdk = Build.VERSION.SDK_INT; // do lorem, Eclair-style String l = super.doLorem(); if (sdk <= Build.VERSION_CODES.ECLAIR) { } // additional processing li = new EclairLoremIpsum(); public abstract int doIpsum() { return l; } else if (sdk <= // deliver ipsum, a là Eclair } Build.VERSION_CODES.FROYO) { } public abstract int doIpsum() { li = new FroyoLoremIpsum(); } ... } else { li = new GingerbreadLoremIpsum(); } )Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 59
  60. 60. Resources are your best friend, use them. Utilisez des booléens pour savoir quelle est la version du système. Ils s’utilisent dans le code et dans le Manifest.xml. Resvalues-v14bools.xml Resvaluesbools.xml <?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?> <resources> <resources> <bool name="postICS">true</bool> <bool name="postICS">false</bool> <bool name="preICS">false</bool> <bool name="preICS">true</bool> </resources> </resources> SomeWhere in java Manifest Resources res = getResources(); <receiver android:name="MyPreICSAppWidget" boolean postICS = android:enabled="@bool/preICS"> res.getBoolean(R.bool.postICS); ... if (postICS) { </receiver> // do something cool and cutting-edge <receiver android:name="MyPostICSAppWidget" } else { android:enabled="@bool/postICS"> // do something old-school but elegant! ... } </receiver>Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 60
  61. 61. Hériter du thème de la version. Restez cohérent avec le thème du SDK de l’appareil cible, conservez une application cohérente avec l’appareil. resvalues-v11theme.xml MyTheme <style name="MyAppThemeBase" parent="@android:style/Theme.Holo" /> <style name="MyButtonStyle" parent="@android:style/Widget.Holo.Button"> MyBaseTheme resvaluestheme.xml <style name="MyAppThemeBase" parent="@android:style/Theme" /> <style name="MyAppTheme" parent="MyAppThemeBase"> <style name="MyButtonStyle" parent="@android:style/Widget.Button"> Theme Theme.HoloMultiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 61
  62. 62. Utiliser les Fragments et l’ActionBar sur toutes vos versions. Ayez une application identique quelque soit la version du système et utilisez le même fichier de layout. public class BaseActivityHC extends Activity{...} public class BaseActivityLegacy extends android.support.v4.app.FragmentActivity {...} android.support.v4.app.ActionBarActivity public class SpeakerDetailFragmentHC extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.speaker_detail, container, false); return view; } public class SpeakerDetailFragment extends android.support.v4.app.Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.speaker_detail, container, false); return view; }Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 62
  63. 63. Utiliser les notifications PreJB, PostJB. Utilisez les notifications sur toutes les versions avec le NotificationCompat.Builder. Les notifications sont une des grandes évolutions de JellyBean. Le NotificationBuilder a été délivré pour HC, mais si vous voulez profitez des évolutions sur toutes les versions, il faut utiliser le NotificationCompat.Builder. if version >= JellyBean use Notification.Builder else use NotificationCompat.Builder private void pushInboxNotifications() { Notification notification = new Notification.Builder(this) .setContentTitle("10 New emails for me") .setContentText("subject") .setSmallIcon(android.R.drawable.ic_menu_agenda) .setStyle(Notification.InboxStyle) .addLine("Line 1, i can add more if i want") .addAction(R.drawable.icon,R.string.notification_message,new PendingIntent(....)) .setSound(aSound) .build(); NotificationManager notificationManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, notification); }Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 63
  64. 64. L’ordre des boutons a changé depuis ICS. Avant ICS le bouton OK est à gauche, le bouton non ou cancel à droite. Après ICS le bouton OK est à droite, le bouton non ou cancel à gauche.Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 64
  65. 65. Min, max et target SDK importe. Définissez toujours votre targetSdk comme le plus haut possible pour profiter des nouveautés du système. En d’autres termes, toujours tester votre application avec la plus haute version du système et si elle fonctionne, définissez votre targetSDK comme étant celui-là. <uses-sdk android:maxSdkVersion="16" android:minSdkVersion="8" android:targetSdkVersion="16" /> ps: le maxSDK sutilise uniquement pour proposer différents apk en fonction de la version du système au niveau de GooglePlay.Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012 65
  66. 66. 66
  67. 67. Ne pas oublier le projet de Tests.L’architecte a à charge la conception de l’application mais aussi la conception de l’application de test. Ne loubliez pas. Pour aller plus loin, vous pouvez acheter : Android An Entreprise Edition Vision 67
  68. 68. Ces outils sont : • Le SDK de Test fourni par Android, • JUnit 3 (intégré au SDK d’Android), • Maven pour construire l’application, • Jenkins pour lancer Maven et passer les tests sur différents émulateurs 68
  69. 69. Communauté Google+ Android projects on Github Github open source projectshttps://plus.google.com/u/0/communities/100609058582053363304 69
  70. 70. Cette conférence utilise les références suivantes :Les EBooks et tutoriels d’Android2ee : http://www.android2ee.comLes sites de référence Android: • http://developer.android.com/index.html • http://android-developers.blogspot.fr/ • http://www.google.com/events/io/2011/sessions.html • https://developers.google.com/events/io/sessionsSur Android2ee, vous trouverez les tutoriels libres suivants pour approfondir les notions présentées: • Les capteurs • Les thread de traitement (Handler et fuite mémoire) • Les AppWidgets • Construction dynamique d’IHM • Service REST • Lecteur de flux RSS • Le fichier POM pour mavéniser vos projets • Comment préparer ses livraisons sur GooglePlaySur developpez.com vous trouverez les articles du conférencier : • Déployer son application Android et obtenir sa clef MapView. • Construire dynamiquement ses IHM Android • Les capteurs Android • Thread, Handler, AsyncTask et fuites mémoires • Investir lécran daccueil Android avec les AppWidgets • Android, Livrer son projet sur GooglePlay 70
  71. 71. Merci pour votre attention. android2ee.com. #android2ee Jcertif Mobile sur GooglePlayMySensors, MyLight et MyTorch mathias.seguy@android2ee.com disponible sur GooglePlay 71

×