• 30 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 21/05/2021

Analysez la pile après un plantage

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction

Vous codez paisiblement en pyjama dans votre canapé quand soudain, votre application plante ! Eh oui, cela arrive, même aux meilleurs. Lors d'un plantage, un énorme pavé de texte bien rouge s'affiche dans le logcat d'Android Studio. Dans ce chapitre, nous allons apprendre à analyser ce type d'erreur puis apporter une correction.

La notion de pile d'exécution

Suivant les langages de programmation que vous connaissez, la notion de pile d'exécution (ou call stack en anglais) vous est probablement familière. Dans le cas contraire, il est nécessaire de comprendre ce principe.

Une pile d'exécution permet de mémoriser l'enchaînement d'appel des méthodes (ou fonctions) d'un programme. Pour ce faire, une structure de données de type pile (ou LIFO en anglais, pour Last In First Out) est utilisée. Ce mécanisme permet donc de garder une trace des fonctions appelées, afin de pouvoir "revenir sur ses pas" lorsqu'une fonction est terminée.

Pour illustrer cela, nous allons prendre un exemple assez schématique. Imaginez que vous ayez une fonction (ou méthode, cela importe peu) nommée getTemperature() qui vous renvoie la température extérieure. Cette fonction utilise une autre fonction getTemperatureFromSensor(), qui permet d'interroger le thermomètre. Enfin, la fonction getTemperatureFromSensor() utilise une dernière fonction nommée convertDegreesToCelsius() qui convertit en degrés Celsius une température initialement en degrés Farenheit. Le code simplifié correspondant serait :

int getTemperature() {
return getTemperatureFromSensor();
}
int getTemperatureFromSensor() {
int farenheitTemperature = sensor.getTemperature();
return convertDegreesToCelsius(farenheitTemperature);
}
int convertDegreesToCelsius(int farenheit) {
return (farenheit - 32) * 5 / 9;
}

Lorsque vous appelez la fonction getTemperature(), elle est automatiquement ajoutée à la pile. La pile contient donc :

Pile

getTemperature

Ensuite, au sein de la fonction getTemperature(), c'est au tour de la fonction getTemperatureFromSensor() d'être appelée. Elle est également ajoutée à la pile. La pile contient donc :

Pile

getTemperatureFromSensor

getTemperature

Enfin, c'est au tour de la fonction convertDegreesToCelsius() d'être appelée. Après avoir été ajoutée à la pile, cette dernière contient donc :

Pile

convertDegreesToCelsius

getTemperatureFromSensor

getTemperature

À la fin de l'exécution d'une fonction, elle est "dépilée", c'est à dire qu'elle est retirée de la pile. Il est donc possible de retrouver la fonction appelante.

Analyse d'un plantage

Il est temps de passer aux choses sérieuses. En l'état, l'application MemeTastic fonctionne correctement. Taquins que nous sommes, nous allons lui forcer un peu la main pour qu'elle se plante lamentablement. Ouvrez le fichier MainActivity.java, repérez la ligne 139, puis commentez-la :

// _tagValues = getResources().getStringArray(R.array.meme_tags__titles);

Cette ligne permet de récupérer la liste des titres à utiliser pour chaque onglet de l'application.

Démarrez l'émulateur ou branchez un équipement réel, lancez l'application, puis observez. Si tout se passe bien (ou plutôt si tout se passe mal), vous devriez voir à l'écran un joli message du style MemeTastic has stopped. Et si vous regardez du côté du logcat, vous devriez également voir un joli pavé de ce type :

Bravo ! C'est un magnifique plantage. Reste à comprendre pourquoi. Si vous y regardez de plus près, vous pourrez trouver la cause du plantage. La ligne qui nous intéresse pour cela commence par Caused by :

Caused by: java.lang.NullPointerException: Attempt to get length of null array

Nous y découvrons que le plantage est dû à la récupération de la taille d'un tableau. Or ce tableau n'existe pas. Si vous regardez juste en dessous ce cette ligne, vous verrez apparaître le contenu de la fameuse pile. Chaque entrée dans la pile apparaît sur une ligne spécifique, qui commence par at. Les appels les plus récents sont en haut et les plus anciens en bas :

at io.github.gsantner.memetastic.activity.MainActivity.onCreate(MainActivity.java:154)
at android.app.Activity.performCreate(Activity.java:6980)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6540)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)

La première ligne de la pile correspond à l'appel de la méthode onCreate(). Tiens donc, c'est justement dans cette méthode que nous avions commenté une ligne de code ! Pour connaître l'endroit exact du plantage, Android Studio nous aide grandement : il nous indique le nom du fichier et la ligne qui a causé le plantage. Vous pouvez même cliquer dessus pour vous y rendre directement. La ligne incriminée est la suivante :

for (String cat : _tagValues) {

Forcément, nous cherchons à itérer sur le contenu d'un tableau qui n'existe pas ! Car nous avons commenté la ligne permettant de l'initialiser. Dans ce cas précis, nous savons tout de suite d'où vient l'erreur. En temps normal, nous nous serions posé la question suivante : "pourquoi la variable n'est-elle pas initialisée ?". Il nous aurait suffi de remonter dans le code pour trouver et comprendre l'origine du problème.

Conclusion

Dans la majorité des bugs que vous allez rencontrer, la cause de l'erreur est généralement assez explicite. Si le message ne vous parle pas du tout, ayez toujours le réflexe suivant : copiez-le puis collez-le sur Google. Vous trouverez très probablement une personne qui a posté sur Stack Overflow et qui a rencontré le même problème que vous.

Exemple de certificat de réussite
Exemple de certificat de réussite