Comme chacun le sait, la méthode de débuggage probablement la plus commune (quelque soit le langage), est d'utiliser des primitives d'affichage sur la sortie standard. Qui ne se rappelle pas des fameux printf
du langage C ou des NSLog
de l'Objective-C ? Le langage Java offre également la même possibilité grâce à des méthodes de type print
du package System.out
.
Le développement sur Android ne déroge pas à la règle puisque le SDK fournit une classe nommée android.util.Log
qui inclue un bon nombre de méthodes d'aide au développement données dans la liste ci-dessous :
Log.v
: Affiche le message en mode “verbose” c'est à dire “verbeux” ou “abondant” en françaisLog.d
: Affiche le message en mode “debug”, utilisé pour le débuggageLog.e
: Affiche le message en mode “error” (erreur)Log.w
: Affiche le message en mode “warning”, c'est à dire les avertissementsLog.i
: Affiche le message en mode “info”
L'utilisation de ces méthodes n'est pas à prendre à la légère. En effet, l'utilisation abusive de ces méthodes engendre un ralentissement du temps d'exécution de votre application. De plus, il faut bien prendre en compte les différences entre ces méthodes. Les méthodes v
et d
ne doivent être utilisées que lors du développement et ne surtout pas être présentes lors de la diffusion de votre programme (sur l'Android Market par exemple). Les méthodes e
, w
et i
peuvent être présente dans une application en “release” mais de façon “limitée” afin de ne pas ralentir inutilement l'application. En conclusion, malgré leur efficacité redoutable (en comparaison d'un débogueur conventionnel), ces méthodes sont à utiliser avec parcimonie et de façon intelligente.
Lorsque vous utilisez cette méthode commune de débuggage, vous êtes confronté à un problème. En effet, malgré l'étonnante efficacité de ce type de débuggage, lorsque vous souhaiter passer votre application en “release” (c'est à dire que vous êtes sur le point de la diffuser), vous devez supprimer l'ensemble des méthodes Log.x
. Malheureusement, seule une recherche manuelle suivie d'une suppression des lignes contenant les Log.x
est possible. Cette démarche est longue et sujette à erreur. Je vais donc vous présenter quelques astuces pour contourner le problème.
Une astuce pour supprimer facilement les Log.x
Lorsque vous souhaitez supprimer tous les appels à ces méthodes d'affichage, il peut être assez pénible de rechercher toutes les occurrences à Log.x
. Une technique consiste à utiliser le modèle suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
L'utilisation de cette astuce consiste en réalité à “exporter” l'affichage des logs dans une méthode externe : log
. Cette méthode n'affiche les logs que si au moins une des deux variables LOGV ou Config.LOGV est à true. L'astuce semble pourtant n'apporter qu'un très faible avantage : celui de ne pas avoir à réécrire Log.d(LOG_TAG,
. Eh bien en fait ce n'est pas tout ! Si on utilise un décompilateur sur le bytecode Java, on se rend compte que le compilateur supprime purement et simplement le bloc conditionnel if (isLogged) { ... }
si la variable isLogged
est à false
. Cela provient du fait que la variable isLogged est déclarée en static final
(constante). Le compilateur “comprend” donc que le bloc conditionnel est inutile et “transforme” alors la méthode log(String log)
en une méthode vide.
Pour conclure, cette astuce se résume de la façon suivante :
- Si isLogged est à
true
(c'est à dire qu'une des deux variablesLOGV
ouConfig.LOGV
est àtrue
) alors le compilateur génère la méthodelog(String log)
de la façon donnée ci-dessous. Cela revient donc à afficher les logs par une indirection (appel àlog
au lieu deLog.x
directement).
1 2 3 4 5 |
|
- Si isLogged est à
false
, le compilateur “vide” totalement la méthodelog(String)
. Votre programme fait alors des appels à une méthode vide. Le temps perdu pour ces appels inutiles est négligeable en comparaison du lancement d'uneActivity
vide par exemple - ratio de l'ordre 15 pour 3 000 000.
1 2 |
|
C'est pratique mais attention !
Cette astuce comporte néanmoins une contrepartie. En effet, elle n'empêche pas la création d'objets même si ces derniers sont inutiles. Prenons l'exemple suivant en supposant que isLogged
est à false
(et donc que la méthode log(String)
est vide) :
1 2 3 |
|
Si on compile puis décompile ce code, on s'aperçoit que le code résultant est le suivant :
1 2 3 |
|
Le code généré créé donc un nouvel objet StringBuilder
auquel on ajoute l'entier i
. Le compilateur n'a pas été assez intelligent pour “deviner” que cette portion de code n'était pas nécessaire et instancie alors des objets inutiles. Cette création d'objets s'accompagne alors d'un possible passage du ramasse-miettes et d'un ralentissement hypothétique de votre programme.
Conclusion
La méthode “ultime” pour éviter de devoir supprimer les Log.x
serait d'inclure le contenu de la méthode log(String)
dans votre code. Le compilateur supprimera alors purement et simplement les bloc conditionnel si isLogged
est à false
. De cette façon, il n'y a aucune instanciation de StringBuilder
. Cela implique que votre code compilé est parfaitement sain mais votre code source un peu plus lourd :
1 2 3 4 5 |
|
Les astuces que je viens de vous donner ont leurs avantages et leurs désavantages. Je pense que les éléments donnés ici vous permettront de mieux appréhender ce que fait le compilateur et d'en déduire la méthode la plus appropriée dans votre cas. Bon débuggage ! ;).