Rien de technique pour cet article ! Je souhaitais simplement souhaiter de joyeuses fêtes à tous les lecteurs de ce blog. L’année 2009 a été tout simplement ce qu’on pourrait appeler une “année Android”. Avec la sortie de pas moins de 4 versions de système (1.5, 1.6, 2.0 et 2.0.1). Le nombre de terminaux sous Android a également suivi cette tendance et j’espère sincèrement (j’en suis même certain) que l’année 2010 sera considérée comme l’année du véritable décollage d’Android…

En 2009 (ou plutôt depuis février 2009) ce sont pas moins de 27 articles techniques sur Android qui ont été posté ici. Au vu de certains des commentaires, je pense avoir atteint en partie l’objectif que je recherchais en lançant ce blog : conseiller les développeurs sur les bonnes pratiques de développement Android. J’espère que vous avez appréciés tous ces articles et que vous continuerez à en lire de nouveaux au cours de 2010.

Bonne fêtes à vous tous

Même si cela peut paraitre un peu contradictoire dans un contexte de langage objet comme Java, minimiser le nombre d’allocations dans son programme impacte grandement sur les performances d’une application Android. Il me semblait essentiel de rédiger un article présentant cette nécessité et exposant quelques régles élémentaires à suivre.

Lorsqu’on me demande mon avis sur la VM Android j’aime utiliser l’expression : “la VM Android est tout ce qu’il y a de plus élémentaire !”. En effet, à force de jouer avec cette dernière on se rend compte qu’elle n’est pas ultra performante : c’est une simple VM interprétée. Le garbage collector (GC) n’est pas plus développé puisque c’est un basique GC “mark and sweep” (pas de GC générationnel par exemple). Android n’inclut pas non plus de technologies telles que la compilation JIT (Just In Time) ou les optimisations à la compilation (caching de variables constantes de boucle, etc.) … Pour résumer, la VM Android ressemble un peu aux premières VMs Java qui aient existé sur cette Terre ! Elle dispose néanmoins d’un énorme avantage : elle fonctionne :).

Android ne repose donc pas sur une base “ultra” performante. Ainsi le GC prend, en règle général environ 100ms à s’exécuter bloquant totalement l’exécution du programme. Cela peut paraitre dérisoire mais bloquer le thread graphique pendant 100ms provoque généralement une forme de mécontentement chez certains tous les utilisateurs ^^. Imaginez une image se déplaçant uniformément du point supérieur gauche de l’écran au point inférieur droit en 500ms. Sur un écran de 320×480 pixels, l’image parcourt environ (comme quoi Pythagore est toujours utile) sqrt(320^2 + 480^2) ≈ 577 pixels en 500ms soit environ 115 pixels toutes les 100ms. Dans le cas où le GC s’exécute durant l’animation, un blocage se fait ressentir … votre image va tout simplement “sauter” 115 pixels faisant croire à une cassure de l’animation.

Lorsque vous développez votre interface graphique, vous devez faire en sorte que cette dernière soit la plus fluide possible. Rendre une interface graphique fluide plusieurs technique dont la principale consiste à empêcher le GC de s’exécuter.Malheureusement pour les développeurs d’UI, le GC est une composante principale du Java. Il n’est pas possible de le supprimer. L’astuce consiste donc à le contourner en n’allouant/désallouant aucune ressource lorsqu’une animation (scrolling de liste, de menu, animation basique, etc.) est en cours. L’intérêt de cet article est de montrer certaines techniques permettant de satisfaire la précédente astuce.

Créer les objets au plus tôt

Il m’arrive régulièrement de lire du code ressemblant au suivant :

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
 
    // ...
 
    Paint paint = new Paint();
    paint.setColor(Color.BLACK);
    canvas.drawText(mText, 20, 20, paint);
 
    //...
}

Créer l’objet de type Paint dans la méthode onDraw(Canvas) (méthode considérée comme “critique” puisqu’elle est appelée très souvent) ralentit extrêmement l’exécution du programme et provoque des GCs lorsque trop d’objets de type Paint ont été créés. Préparer les objets (Paint, Rect, Runnable, etc.) dès la création de l’instance est bien souvent la seule chose à faire pour résoudre ce problème :

public class MyView extends View {
 
    private final Paint mPaint = new Paint();
 
    public MyView(Context context) {
        mPaint.setColor(Color.BLACK);
        // ...
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
       super.onDraw(canvas);
 
       // ...
       canvas.drawText(mText, 20, 20, paint);
       //...
    }
 
}

Maitrisez l’auto-boxing/unboxing

Java 1.5 inclut une fonctionnalité qui facilite grandement le développement : l’auto-boxing/unboxing des types primitifs. Prenons l’exemple ci dessous :

private HashMap<Integer, String> mHashMap;
public MyObject() {
    mHashMap = new HashMap<Integer, String>();
    mHashMap.put(1, "My String 1");
    mHashMap.put(40, "My String 2");
    mHashMap.put(567, "My String 3");
}

Ajouter de nouveaux couples (clé,valeur) à notre HashMap se fait de façon déconcertante puisque Java utilise le type primitif int comme clé. Comment cela est-il possible puisque les clés ne peuvent normalement être que des objets (dans notre cas de type Integer). En réalité, Java 1.5 créé un objet de type Integer ne contenant qu’un int. C’est ce qu’on appelle l’auto-boxing. Malheureusement, cela signifie que Java créé des objets “inutilement”.

Pour contrer ce problème essayer de créer vos propres structures de données à base de tableaux élémentaires (oui oui je parle des tableaux avec les [] et non pas de LinkedList, Vector ou autre ArrayList). Dans l’exemple ci-dessus, il est également possible d’utiliser un objet extrêmement pratique disponible dans android.util : SparseArray. Il permet de “mapper” des objets à des int (servant de clés) même s’il existe des gaps entre les clés.

Attention aux Strings

Le type String est un type un peu spécial en Java. En effet, ce n’est pas réellement un type primitif mais le langage l’intègre tellement bien qu’il s’utilise comme tel. En réalité, les objets de type String sont “immutables”. Cela signifie qu’ils ne peuvent tout simplement pas être modifiés. L’exemple suivant implique donc une création de nouvelles Strings à chaque tour de boucle :

private String mStrings[];
 
@Override
public String toString() {
    final int count = mStrings.length;
    String res = "";
    for(int i = 0; i < count; i++) {
        res += mStrings[i];
    }
    return res;
}

L’utilisation d’objets “mutables” tels que StringBuilder accélère grandement l’exécution du programme en minimisant la création d’objets :

private String mStrings[];
 
@Override
public String toString() {
    final int count = mStrings.length;
    StringBuilder builder = new StringBuilder();
    for(int i = 0; i < count; i++) {
        builder.append(mStrings[i]);
    }
    return builder.toString();
}

Réutilisez les objets inutiles

La dernière règle élémentaire qui, de mon point de vue, est LA règle à ne pas oublier sur terminaux mobiles se résume en un mot : Réutilisez ! Lisez bien la documentation Android car certaines méthodes comme View getView (int, View, ViewGroup) de la classe Adapter fournissent des objets à réutiliser. Dans le cas d’une liste par exemple, dans laquelle chaque cellule est une View, il est beaucoup plus rapide de modifier le contenu de la vue que de créer une nouvelle View “from scratch” (ce qui implique généralement de faire un “inflate” d’une ressource XML - démarche longue et douloureuse pour le terminal).

Je pense avoir donné ici les principaux points qui me sont venus à l’esprit au moment de la rédaction de cet article. J’aurais aimé en écrire plus sur ce domaine mais je crois plus raisonnable de laisser une seconde partie pour de futurs articles. Je ne peux maintenant que vous souhaitez “bon codage” ! Codez bien, codez avec votre tête ^^.

Tous les lecteurs de ce blog l’auront remarqué : les posts que je rédige sont principalement techniques et ne traitent donc pas vraiment de sujets autres que le framework applicatif Android ou les outils de développement associés. Il existe néanmoins quelques exceptions à la règle comme notamment mon coup de gueule envers les sociétés ne sachant pas écrire “Android” ou la mise à disposition de ressources graphiques.

Pourquoi ne pas parler de technique dans ce post ? Tout simplement parce que trop de technique tue le technique et qu’il m’arrive assez souvent de penser d’un point de vue plus global sans exprimer mes idées. N’essayons pas non plus de percer tous les mystères d’Android en une seule fois : laissons en pour un prochain post ! C’est dans cette même optique d’ouverture que j’ai souhaité rédigé ce petit post présentant le Motorola Dext.

Grâce au merveilleux programme “Android Influencer” lancé par Motorola, j’ai récemment eu la joie d’être contacté afin de tester un Motorola Dext. Il me parait donc intéressant de donner mon point de vue sur ce terminal.

Avant de commencer, j’aimerai donner la liste exhaustive des terminaux Android que j’ai eu, au jour d’aujourd’hui, l’occasion de tester. Ce sont ces terminaux qui me servent de base pour appuyer mes dires :

  • Le HTC G1 (Dev Phone v1)
  • Le HTC Magic
  • Le Samsung Galaxy
  • Le Samsung Spica
  • D’autres terminaux qui ne sont même pas encore connus du grand public …

Commençons tout d’abord par le point de vue matériel. La première chose qui m’a choqué lorsque j’ai pris ce terminal en main c’est son poids. Il est assez lourd et j’aurais même tendance à dire que c’est le terminal Android le plus lourd que j’ai eu l’occasion de tester. Le terminal rassure beaucoup plus que l’HTC G1 sur lequel on a l’impression d’arracher l’écran à chaque ouverture du clavier physique … Ici la conception parait NETTEMENT plus solide (cela explique peut-être le poids aussi important). Malheureusement ce clavier peine à convaincre car il ne permet pas de taper rapidement (je ne suis pas un grand amateur des claviers à touches bombées). L’écran tactile est réactif et affiche des couleurs vraiment très contrastées. Si je devais classer les terminaux précédemment listés du meilleur au moins bon écran, j’aurais tendance à classer le Samsung Galaxy en premier (écran AMOLED oblige) et le Motorola Dext ensuite.

L’autre point sur lequel Motorola a souhaité se différencier c’est l’interface graphique. Globalement, je suis agréablement surpris par la fluidité de l’ensemble et le style “Motorola” donné à l’interface MotoBlur. Une attention particulière a été donné à la réalisation de l’interface et le résultat final est vraiment meilleur que notre Android “classique”. Les concepts ergonomiques bien connus d’Android ont été améliorés pour le plus grand bonheur des utilisateurs. MotoBlur pousse parfois même un peu trop la porte de l’innovation ou du conceptuel avec des animations pas toujours très “smooth”.

J’aimerai terminer sur l’inter-connection de MotoBlur et des réseaux sociaux style Facebook ou Twitter. Après une brève installation, on accède directement depuis son mobile à tous les principaux réseaux sociaux. Cette fonctionnalité est vraiment bien intégrée au téléphone et très facile d’utilisation.

Le bilan général est positif : Motorola a conçu une machine sous Android 1.5 qui est vraiment très “user-friendly” et tout cela sans l’aide de Google ! Si les autres constructeurs réussissent aussi bien l’intégration et le “tweaking” du système de l’Open Handset Alliance dans leurs terminaux, il y a fort à parier qu’Android sera présent dans beaucoup de mains innocentes d’ici peu !