Sur la route d'Oxiane digressions diverses

LeBlog OXiane

24 mar
2011

C’est quoi un Objet ?

Nos échanges internes, souvent passionnés (et parfois alcoolisés) du soir nous ramènent souvent à la question fondamentale « c’est quoi un objet (en informatique) ? »
et autres sous-question du genre « c’est quoi la différence entre le sous-typage et l’héritage ? » ou « c’est quoi un type ? »

Sur l’objet, un dessin vaut mieux qu’un grand discours …

La réponse un peu mieux expliquée …

Les vrais fondements

1/ l’encapsulation
Les données internes et privée de l’objet (à ne pas confondre avec l’agrégation ou la composition comme malheureusement je le vois avec horreur dans certaines réponses à nos tests d’évaluation)

2/ l’envoi de message
Les objets sont sollicités par envoi de message et ce sont eux qui déterminent le traitement à effectuer

Le reste n’est pas fondamental mais en découle plus ou moins :

3/ le polymorphisme
Un objet peut être remplacé par un autre qui sait répondre aux messages attendus
Conséquence du 2 (le même message peut être envoyé à des objets différents et c’est l’objet receveur qui détermine la méthode à exécuter)

4/ le mécanisme d’héritage
Consiste à éviter de recopier les mêmes méthodes dans des objets différents.
Les langages à base de classe (ndr: comme Java, smalltalk, php) proposent une relation d’héritage entre classes (les méthodes sont portées par les classes et les objets sont instances de ces classes)
Les langages à base de prototype (ndr: comme javascript) font porter les méthodes par les objets directement mais les objets font références à des prototypes (la recherche de méthodes est déléguée au prototype lorsque l’objet ne trouve pas la méthode correspondant au message reçu).

Qu’en est-il du typage ?
Le typage n’est pas une notion objet. C’est une notion de compilation.
Ce qu’on type, ce sont des variables, paramètres et retours de traitements (fonction, méthode, procédure)
Dans un système objet à base de classes, les classes servent généralement aussi de type.
Et la relation d’héritage correspond un peu à la notion de sous-type.

Par abus de langage, on parle parfois de typage dynamique dans les langages à objets non typés.
Java a formalisé le concept d’interface (qui correspond à la notion de type abstrait)
ce qui dissocie un peu plus encore le typage de l’héritage.

Article honteusement inspiré d’échanges sur la mailing liste interne et d’une réponse synthétique de Jean-François

Stéphane Liétard

slietard

31 jan
2011

Organiser les accès aux données sous Android

En réalisant une application « Cave à vins » sous Android, je me suis trouvé face à un problème de taille: comment faire passer mes objets métiers d’une Activity à l’autre en gardant un code maintenable?

Tout dans les Intents!

Ma toute première approche a été de tout envoyer dans les Intents, à chaque changement de vue, j’ai envoyé des ArrayLists d’objets métier entiers. Je me suis vite rendu compte que ça devenait rapidement ingérable. Il faut traiter trop de cas différents dans chaque page: que se passe-t-il avec mes données si l’utilisateur clique sur « back »?
Intent i = new Intent(DisplayDetail.this, MarkedMap.class);
ArrayList<Marker> mm = new ArrayList<Marker>();
mm.add(new Marker(1, 2, 3));
i.putParcelableArrayListExtra("markers", mm);
startActivityForResult(i, CODE_REQ_MARKER);

Avec un ContentProvider

Ma seconde approche fut d’utiliser un Content Provider, puisque son nom dit qu’il fournit des données, ça devrait être ce que je veux. Ca a l’air super, y’a une méthode « managedQuery » qu’on peut appeler de n’importe quelle Activity. Le souci, c’est qu’il fournit des objets de type Cursor. Et là, si on a besoin dans deux Activity de la liste des Personnes, on doit écrire deux fois la boucle sur le Cursor:
Cursor cur = managedQuery(myPerson, null, null, null, null);
if (cur.moveToFirst()) {

        String name;
        String phoneNumber;
        int nameColumn = cur.getColumnIndex(People.NAME);
        int phoneColumn = cur.getColumnIndex(People.NUMBER);
        String imagePath;

        do {
            // Get the field values
            name = cur.getString(nameColumn);
            phoneNumber = cur.getString(phoneColumn);

            // Do something with the values.
            ... 

        } while (cur.moveToNext());

    }

(exemple pris sur developer.android.com)

Et ça, c’est terrible. Si un jour on change le modèle métier des Personnes, faut réécrire ce code dans CHAQUE Activity.

L’héritage, tout simplement

Vous me direz, mais pourquoi ne pas avoir une superclass qui s’occupe de tout ça et qui renvoie des objets métiers comme on veut? Ca semble être une super idée, on a une classe qui contient un ensemble de méthodes pour récupérer, lister, modifier nos objets Personne. Et puis toutes les Activity qu’on crée qui ont besoin de ces Personnes héritent de notre superclasse. Si on veut faire les choses bien, on peut même envisager que la super classe est abstraite et qu’on a une flopée de classes du style « DAOimpl » qui vont aller chercher les données dans un flux xml, la base de donnée interne SQLite ou encore un webservice ou que sais-je?
C’est une bonne idée, à un détail près: sous Android, quand on passe d’une Activity à l’autre, ce n’est pas le développeur qui appelle explicitement le constructeur de l’Activity. C’est géré de façon interne (et obscure à mes yeux!), avec un classloader. Le développeur ne fait qu’appeler « startActivity(Intent i…) » ou encore « startActivityForResult(Intent i….) » et c’est à peu près tout ce qu’on peut contrôler sur l’instanciation de l’Activity.
Et donc si dans la superclasse on gère une collection de Personne, on risque fortement (pour ne pas dire inévitablement) d’avoir plusieurs collections de Personne qui se baladent en mémoire de façon parallèle! Et donc éventuellement une des instances de la collection qui sera modifiée par une Activity, une autre instance de la collection de Personne par une deuxième Activity…
Enfer et damnation, ce n’est donc toujours pas la bonne solution.
La solution, c’est d’utiliser un service. Le service Android, c’est comme un thread qui tourne en parallèle de votre application, qui peut soit être lancé et s’arrêter en même temps que chaque Activity, soit tourner indéfiniment, jusqu’à ce qu’on lui dise explicitement de s’arrêter.
Donc, l’idée, c’est que chaque vue qui a besoin des Personnes se connecte au service:
Intent dbServiceIntent = new Intent("com.oxiane.service.DBService");
ServiceConnection conn = new ServiceConnection() {
			@Override
			public void onServiceConnected(ComponentName name,IBinder service) {
				Log.d("dbService", callingClassName + " Connected");
				dbService = ((DBService.MyServiceBinder) service).getService();
				serviceConnectionIsReady();
			}

			@Override
			public void onServiceDisconnected(ComponentName name) {
				Log.d("dbService", callingClassName + " Disconnected");
			}
		};
bindService(dbServiceIntent, conn, Context.BIND_AUTO_CREATE);

Note: la méthode serviceConnectionIsReady() est une méthode que j’ai mise en abstraite dans la superclass de mes Activity. Chaque Activity va donc devoir l’implémenter. Un bon exemple d’utilisation est, par exemple, d’afficher une barre de progression « Loading… » puis, dans la méthode serviceConnectionIsReady(), vous avec accès à vos données, donc vous pouvez afficher votre vue avec les données.

Il reste encore un souci: dans ce cas d’utilisation, chaque Activity qui appelle ce bout de code va lancer le service et l’arrêter quand l’Activity meurt. Ce qu’on veut, nous, c’est que le service soit lancé tout le temps, et que chaque Activity puisse à sa guise, se connecter ou non au service.

On pourrait faire simplement un « startService » dans un coin, sur la première Activity de l’application. Mais ce serait trop simple, non? Et on risque d’oublier que c’est dans telle ou telle Activity que le service est démarré. Et il faudrait changer de place ce code si on décide que c’est finalement une autre Activity qui se lance en premier…

Au lieu de ça, il suffit de vérifier si notre service « com.oxiane.service.DBService » est lancé ou non:

Lister les services qui tournent sur votre machine

Il y’a justement un service Android qui est fait pour ça! Le service ACTIVITY_SERVICE:

final ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
final List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);

Et voilà, plus qu’à parcourir cette liste, et on peut lancer le service s’il n’existe pas, ou s’y connecter s’il existe!

for (int i = 0; i < services.size(); i++) {
if ("com.oxiane.service.DBService".equals(services.get(i).service.getClassName())) {
isServiceFound = true;
break;
}
}
if(isServiceFound)
{
Log.d("oxianeService", "Service trouvé, je me connecte!");
bindService(dbServiceIntent, conn, Context.BIND_AUTO_CREATE);
}
else
{
Log.d("oxianeService", "Service NON trouvé, je le crée puis je me connecte");
startService(dbServiceIntent);
}
Johann Hilbold

jhilbold

26 jan
2011

Comment utiliser les Jakarta Commons dans un plugin Eclipse

Comment peut-on utiliser des librairies tierces telles que commons-lang ou commons-io dans un plugin Eclipse ?

L’approche naïve que l’on trouve généralement via google consiste à embarquer le jar correspondant dans son plugin. Ainsi on peut l’ajouter au classpath du projet et l’utiliser. Inconvénient : chaque plugin embarque toutes ses dépendances, quitte à les ré-exporter, sans aucune gestion commune des dépendances. Bref, je trouve que l’on va un peu à l’encontre de l’esprit d’OSGi.

Eclipse Orbit

Une autre approche que je vous propose ici consiste à piocher dans le projet Eclipse Orbit (http://www.eclipse.org/orbit/). Ce projet essaie justement de mutualiser les librairies tierces pour tous les projets Eclipse et de les proposer sous forme de bundles OSGi. Exactement ce qu’il nous faut ! Nous allons donc ajouter une dépendance vers le plugin org.lalibrairie du projet Orbit au lieu d’embarquer lalibrairie.jar. On peut récupérer des bundles binaires prêts à l’emploi sur le site d’Orbit, mais je préfère récupèrer les librairies Orbit par CVS.

Voici ma procédure  :

  • – Dans la vue CVS repositories (quel que soit votre outil de SCM, le plugin CVS est inclus dans la plupart des distributions d’Eclipse), je crée un nouveau repository CVS à partir de cet URL :
    :pserver:anonymous@dev.eclipse.org/cvsroot/tools
  • - En explorant ce repository, sous HEAD/org.eclipse.orbit, je vois l’ensemble des librairies disponibles.
  • - Je fais un checkout en tant que projet plugin de la (ou des) librairie(s) dont j’ai besoin.
    Par exemple, je prends org.apache.commons.lang, org.apache.commons.io et org.apache.commons.collections.
  • – Pour chaque projet récupéré ainsi, je vais faire un team>switch to another branch pour aller sur la branche correspondant à la version désirée. Par exemple, je bascule org.apache.commons.collections sur la branche v3_2 pour avoir dans mon workspace le bundle correspondant à la version 3.2 de commons-collections.
    Ça doit donner ça dans le workspace :
  • – Le plus gros est fait. Je peux maintenant ajouter très simplement la librairie dans l’onglet dependancies du plugin, comme je dépendrais de tout autre plugin.
  • – Ne pas oublier au moment de livrer d’ajouter les plugins provenant d’Orbit dans le(s) feature(s)


Guillaume Rams
Crédits photo : NASA Goddard Space Flight CenterCertains droits réservés (licence Creative Commons)

Guillaume Rams

Guillaume Rams

21 jan
2011

OXiane Studio : UrbanCycle fête ses 10 ans !

urbancycle a 10 ans

urbancycle a 10 ans

La société des Coursiers à vélo a 10 ans !

Le studio réalise le site internet en PHP depuis les débuts !

UrbanCycle, c’est la première société de coursiers à vélo de France, installée à Paris, elle fait des émules une peu partout dans l’hexagone, elle sait fournir un service irréprochable et sa longévité en est la preuve. Nous sommes fiers de nous occuper du site d’une si belle entreprise. Le week end du 29 Janvier, UrbanCycle fêtera ses 10 ans avec amis et partenaires pour encore de nombreux kilomètres à vélo.

Alain

Alain Boudard

aboudard

18 jan
2011

Le Catalogue OXiane pour Android sur le market

Une petite news pour annoncer le retour de l’application Android Catalogue d’OXiane sur le market Android.

Le Studio est passé par là et a préparé une version un peu plus aboutie graphiquement !

Une simple recherche « oxiane » vous permettra d’installer la dernière version à jour.

Alain Boudard

aboudard