Mesurer le temps de chargement et l'affichage à l'écran avec Firebase Performance Monitoring

1. Introduction

Dernière mise à jour : 11/03/2021

Pourquoi devons-nous mesurer les performances des vues ?

Les vues sont un élément clé des applications Android qui affectent directement l'expérience utilisateur. Par exemple, votre activité ou fragment contient l'interface utilisateur qui contient les composants de la vue avec lesquels les utilisateurs interagissent. Les utilisateurs ne peuvent pas voir l'intégralité du contenu de l'interface utilisateur tant qu'il n'est pas entièrement affiché à l'écran. Les écrans lents et figés nuisent directement à l'interaction des utilisateurs avec votre application et créent une mauvaise expérience utilisateur.

Firebase Performance Monitoring ne fournit-il pas ces métriques de performances prêtes à l'emploi ?

Firebase Performance Monitoring capture automatiquement certaines données de performances prêtes à l'emploi, telles que le temps de démarrage de votre application (c'est-à-dire le temps de chargement de votre première activité uniquement) et les performances de rendu de l'écran (c'est-à-dire les images lentes et figées pour les activités, mais pas pour les fragments). Cependant, les applications du secteur ne comportent généralement pas beaucoup d'activités, mais une seule activité et plusieurs fragments. De plus, de nombreuses applications implémentent généralement leurs propres vues personnalisées pour des cas d'utilisation plus complexes. Il est donc souvent utile de comprendre comment mesurer le temps de chargement et les performances de rendu d'écran des activités et des fragments en instrumentant des traces de code personnalisées dans votre application. Vous pouvez facilement étendre cet atelier de programmation pour mesurer les performances des composants des vues personnalisées.

Points abordés

  • Ajouter Firebase Performance Monitoring à une application Android
  • Comprendre le chargement d'une activité ou d'un fragment
  • Comment instrumenter les traces de code personnalisées pour mesurer le temps de chargement d'une activité ou d'un fragment
  • Comprendre le rendu de l'écran et ce qu'est une image lente/figée
  • Instrumenter des traces de code personnalisées avec des métriques pour enregistrer les écrans lents/figés
  • Afficher les métriques collectées dans la console Firebase

Prérequis

  • Android Studio 4.0 ou version ultérieure
  • Un appareil/émulateur Android
  • Java version 8 ou ultérieure

2. Configuration

Obtenir le code

Exécutez les commandes suivantes pour cloner l'exemple de code de cet atelier de programmation. Cette opération crée un dossier nommé codelab-measure-android-view-performance sur votre ordinateur:

$ git clone https://github.com/FirebaseExtended/codelab-measure-android-view-performance.git
$ cd codelab-measure-android-view-performance

Si git n'est pas installé sur votre machine, vous pouvez également télécharger le code directement depuis GitHub.

Importez le projet measure-view-performance-start dans Android Studio. Vous verrez probablement des erreurs de compilation ou un avertissement concernant un fichier google-services.json manquant. Nous allons corriger ce problème dans la section suivante de cette étape.

Dans cet atelier de programmation, nous allons utiliser le plug-in Firebase Assistant pour enregistrer notre application Android dans un projet Firebase et ajouter les fichiers de configuration, les plug-ins et les dépendances Firebase nécessaires à notre projet Android, le tout depuis Android Studio.

Connecter votre application à Firebase

  1. Accédez à Android Studio/Help > Check for updates (Android Studio/Aide > Rechercher les mises à jour) pour vous assurer que vous utilisez les dernières versions d'Android Studio et de l'Assistant Firebase.
  2. Sélectionnez Tools > Firebase (Outils > Firebase) pour ouvrir le volet Assistant.

E791bed0999db1e0.png

  1. Choisissez Performance Monitoring à ajouter à votre application, puis cliquez sur Premiers pas avec Performance Monitoring.
  2. Cliquez sur Se connecter à Firebase pour associer votre projet Android à Firebase (la console Firebase s'ouvre alors dans votre navigateur).
  3. Dans la console Firebase, cliquez sur Ajouter un projet, puis saisissez un nom de projet Firebase (si vous disposez déjà d'un projet Firebase, vous pouvez sélectionner ce projet existant à la place). Cliquez sur Continuer et acceptez les conditions d'utilisation pour créer le projet Firebase et une application Firebase.
  4. Une boîte de dialogue s'affiche pour vous inviter à associer votre nouvelle application Firebase à votre projet Android Studio.

42c498d28ead2b77.png

  1. De retour dans Android Studio, dans le volet Assistant, vous devriez voir la confirmation que votre application est connectée à Firebase.

dda8bdd9488167a0.png

Ajouter Performance Monitoring à votre application

Dans le volet Assistant d'Android Studio, cliquez sur Add Performance Monitoring to your app (Ajouter Performance Monitoring à votre application).

Une boîte de dialogue Accept Changes (Accepter les modifications) devrait s'afficher. Android Studio devrait ensuite synchroniser votre application pour s'assurer que toutes les dépendances nécessaires ont été ajoutées.

9b58145acc4be030.png

Enfin, le message de réussite s'affiche dans le volet Assistant d'Android Studio, indiquant que toutes les dépendances sont configurées correctement.

aa0d46fc944e0c0b.png

Vous pouvez également activer la journalisation du débogage en suivant les instructions de l'étape "(Facultatif) Activer la journalisation de débogage". Les mêmes instructions sont également disponibles dans la documentation publique.

3. Exécuter l'application

Si vous avez correctement intégré votre application au SDK Performance Monitoring, le projet devrait maintenant se compiler. Dans Android Studio, cliquez sur Run > Exécutez "app" pour compiler et exécuter l'application sur votre émulateur/appareil Android connecté.

L'application comporte deux boutons qui vous permettent d'accéder à une activité et à un fragment correspondants, comme suit:

410d8686b4f45c33.png

Dans les étapes suivantes de cet atelier de programmation, vous allez apprendre à mesurer le temps de chargement et les performances de rendu de l'écran de votre activité ou de votre fragment.

4. Comprendre le chargement d'une activité ou d'un fragment

Au cours de cette étape, nous allons découvrir ce que fait le système pendant le chargement d'une activité ou d'un fragment.

Comprendre le chargement d'une activité

Pour une activité, le temps de chargement est défini comme le temps écoulé entre la création de l'objet Activity et le rendu complet du premier frame à l'écran (c'est à ce moment que l'utilisateur verra pour la première fois l'UI complète de l'activité). Pour déterminer si votre application est entièrement dessinée, vous pouvez utiliser la méthode reportFullyDrawn() afin de mesurer le temps écoulé entre le lancement de l'application et l'affichage complet de toutes les ressources et hiérarchies de vues.

De manière générale, lorsque votre application appelle startActivity(Intent), le système effectue automatiquement les processus suivants. Chaque processus prend du temps, ce qui s'ajoute au temps qui s'écoule entre la création de l'activité et le moment où l'utilisateur voit l'interface utilisateur de l'activité à l'écran.

C20d14b151549937.png

Comprendre le chargement d'un fragment

Comme pour l'activité, le temps de chargement d'un fragment est défini comme étant le temps écoulé entre le moment où le fragment est associé à son activité hôte et jusqu'à ce que le premier frame de la vue de fragment soit complètement dessiné à l'écran.

5. Mesurer le temps de chargement d'une activité

Les retards au début du premier frame peuvent nuire à l'expérience utilisateur. Il est donc important de comprendre le délai de chargement initial rencontré par vos utilisateurs. Vous pouvez instrumenter une trace de code personnalisée pour mesurer ce temps de chargement:

  1. Démarrez la trace de code personnalisée (nommée TestActivity-LoadTime) dans la classe Activity dès que l'objet Activity est créé.

TestActivity.java

public class TestActivity extends AppCompatActivity {   
    // TODO (1): Start trace recording as soon as the Activity object is created.
    private final Trace viewLoadTrace = FirebasePerformance.startTrace("TestActivity-LoadTime");

    // ...

}
  1. Ignorez le rappel onCreate() et obtenez la vue ajoutée par la méthode setContentView().
@Override     
public void onCreate(Bundle savedInstanceState) {    
    super.onCreate(savedInstanceState);          

    // Current Activity's main View (as defined in the layout xml file) is inflated after this            
    setContentView(R.layout.activity_test);          

    // ...

    // TODO (2): Get the View added by Activity's setContentView() method.         
    View mainView = findViewById(android.R.id.content);     

    // ...
}
  1. Nous avons inclus une implémentation de FistDrawListener, qui comporte deux rappels: onDrawingStart() et onDrawingFinish() (voir la section suivante ci-dessous pour en savoir plus sur FirstDrawListener et ce qui peut affecter ses performances). Enregistrez le FirstDrawListener à la fin du rappel onCreate() de l'activité. Vous devez arrêter votre viewLoadTrace dans le rappel onDrawingFinish().

TestActivity.java

    // TODO (3): Register the callback to listen for first frame rendering (see
    //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when View drawing is
    //  finished.
    FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {              
        @Override             
        public void onDrawingStart() {       
          // In practice you can also record this event separately
        }

        @Override             
        public void onDrawingFinish() {
            // This is when the Activity UI is completely drawn on the screen
            viewLoadTrace.stop();             
        }         
    });
  1. Réexécutez l'application. Ensuite, filtrez le Logcat avec Logging trace metric (Métrique de trace Logging). Appuyez sur le bouton LOAD ACTIVITY, puis recherchez des journaux comme ceux ci-dessous :
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Félicitations ! Vous avez mesuré le temps de chargement d'une activité et envoyé ces données à Firebase Performance Monitoring. Nous consulterons la métrique enregistrée dans la console Firebase plus tard dans cet atelier de programmation.

But de FirstDrawListener

Dans la section juste au-dessus, nous avons enregistré un FirstDrawListener. FirstDrawListener permet de mesurer le début et la fin du dessin du premier frame.

Elle implémente ViewTreeObserver.OnDrawListener et remplace le rappel onDraw() qui est appelé lorsque l'arborescence View est sur le point d'être dessinée. Il encapsule ensuite le résultat pour fournir deux rappels utilitaires onDrawingStart() et onDrawingFinish().

Le code complet de FirstDrawListener se trouve dans le code source de cet atelier de programmation.

6. Mesurer le temps de chargement d'un fragment

La mesure du temps de chargement d'un fragment est semblable à celle d'une activité, mais avec quelques différences mineures. Nous allons à nouveau instrumenter une trace de code personnalisée :

  1. Ignorez le rappel onAttach() et commencez à enregistrer votre fragmentLoadTrace. Nous allons nommer cette trace Test-Fragment-LoadTime.

Comme expliqué précédemment, l'objet Fragment peut être créé à tout moment, mais il ne devient actif que lorsqu'il est associé à son activité hôte.

TestFragment.java

public class TestFragment extends Fragment {

   // TODO (1): Declare the Trace variable.
   private Trace fragmentLoadTrace;

   @Override
   public void onAttach(@NonNull Context context) {
       super.onAttach(context);

       // TODO (2): Start trace recording as soon as the Fragment is attached to its host Activity.
       fragmentLoadTrace = FirebasePerformance.startTrace("TestFragment-LoadTime");
   }
  1. Enregistrez le FirstDrawListener dans le rappel onViewCreated(). Ensuite, comme dans l'exemple d'activité, arrêtez la trace dans onDrawingFinish().

TestFragment.java

@Override
public void onViewCreated(@NonNull View mainView, Bundle savedInstanceState) {
   super.onViewCreated(mainView, savedInstanceState);

   // ...

   // TODO (3): Register the callback to listen for first frame rendering (see
   //  "OnFirstDrawCallback" in FirstDrawListener) and stop the trace when view drawing is
   //  finished.
   FirstDrawListener.registerFirstDrawListener(mainView, new FirstDrawListener.OnFirstDrawCallback() {

       @Override
       public void onDrawingStart() {
           // In practice you can also record this event separately
       }

       @Override
       public void onDrawingFinish() {
           // This is when the Fragment UI is completely drawn on the screen
           fragmentLoadTrace.stop();
       }
   });
  1. Réexécutez l'application. Ensuite, filtrez le Logcat avec Logging trace metric (Métrique de trace Logging). Appuyez sur le bouton LOAD FRAGMENT, puis recherchez des journaux comme ceux ci-dessous :
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Félicitations ! Vous avez mesuré le temps de chargement d'un fragment et transmis ces données à Firebase Performance Monitoring. Nous consulterons la métrique enregistrée dans la console Firebase plus tard dans cet atelier de programmation.

7. Comprendre le rendu de l'écran et ce qu'est une image lente/figée

L'affichage de l'interface utilisateur consiste à générer un frame à partir de votre application et à l'afficher à l'écran. Pour que l'interaction de l'utilisateur avec votre application soit fluide, votre application doit afficher des images en moins de 16 ms pour atteindre 60 images par seconde ( pourquoi 60 images par seconde ?). Si votre application souffre d'un affichage lent de l'interface utilisateur, le système est obligé d'ignorer des images, et l'utilisateur perçoit le stuttering dans votre application. C'est ce que nous appelons les à-coups.

De même, les cadres figés sont des cadres d'interface utilisateur qui mettent plus de 700 ms à s'afficher. Ce délai pose problème, car votre application semble être bloquée et ne répond pas à l'entrée utilisateur pendant près d'une seconde complète alors que le frame est en train de s'afficher.

8. Mesurer les frames lents/figés d'un fragment

Firebase Performance Monitoring capture automatiquement les images lentes ou figées pour une activité (mais uniquement s'il s'agit d'une accélération matérielle). Toutefois, cette fonctionnalité n'est pas disponible pour les fragments. Les images lentes/figées d'un fragment sont définies comme les images lentes/figées de l'ensemble de l'activité entre les rappels onFragmentAttached() et onFragmentDetached() dans le cycle de vie du fragment.

En nous appuyant sur la classe AppStateMonitor (qui fait partie du SDK Performance Monitoring responsable de l'enregistrement des traces d'écran pour l'activité), nous avons implémenté la classe ScreenTrace (qui fait partie du dépôt du code source de cet atelier de programmation). La classe ScreenTrace peut être connectée au rappel de cycle de vie FragmentManager de l'activité pour capturer les images lentes ou figées. Cette classe fournit deux API publiques:

  • recordScreenTrace(): commence à enregistrer une trace de l'écran.
  • sendScreenTrace() : arrête l'enregistrement d'une trace d'écran et associe des métriques personnalisées pour consigner le nombre total, lent et figé des images.

En associant ces métriques personnalisées, les traces d'écran des fragments peuvent être gérées de la même manière que les traces d'écran d'une activité et peuvent être affichées avec d'autres traces de rendu d'écran dans le tableau de bord Performances de la console Firebase.

Voici comment enregistrer les traces d'écran de votre fragment:

  1. Initialisez la classe ScreenTrace dans votre activité qui héberge le fragment.

MainActivity.java

// Declare the Fragment tag
private static final String FRAGMENT_TAG = TestFragment.class.getSimpleName();

// TODO (1): Declare the ScreenTrace variable.
private ScreenTrace screenTrace;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // TODO (2): Initialize the ScreenTrace variable.
    screenTrace = new ScreenTrace(this, FRAGMENT_TAG);

    // ...
}
  1. Lorsque vous chargez votre fragment, enregistrez-vous pour FragmentLifecycleCallbacks et remplacez les rappels onFragmentAttached() et onFragmentDetached(). Nous l'avons fait pour vous. Vous devez commencer à enregistrer des traces d'écran dans le rappel onFragmentAttached() et arrêter l'enregistrement dans le rappel onFragmentDetached().

MainActivity.java

private final FragmentManager.FragmentLifecycleCallbacks fragmentLifecycleCallbacks =
       new FragmentManager.FragmentLifecycleCallbacks() {

           @Override
           public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) {
               super.onFragmentAttached(fm, f, context);

               // TODO (3): Start recording the screen traces as soon as the Fragment is
               //  attached to its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.recordScreenTrace();
               }
           }

           @Override
           public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {
               super.onFragmentDetached(fm, f);

               // TODO (4): Stop recording the screen traces as soon as the Fragment is
               //  detached from its host Activity.
               if (FRAGMENT_TAG.equals(f.getTag()) && screenTrace.isScreenTraceSupported()) {
                   screenTrace.sendScreenTrace();
               }

               // Unregister Fragment lifecycle callbacks after the Fragment is detached
               fm.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks);
           }
       };
  1. Réexécutez l'application. Appuyez ensuite sur le bouton LOAD FRAGMENT. Patientez quelques secondes, puis cliquez sur back button dans la barre de navigation inférieure.

Filtrez le logcat avec Logging trace metric (Métrique de journalisation de la trace), puis recherchez des journaux comme ci-dessous :

I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)

Filtrez le Logcat avec FireperfViews, puis recherchez les journaux comme suit:

D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX

🎉 Félicitations ! Vous avez mesuré les frames lents/figés dans un fragment et avez transmis ces données à Firebase Performance Monitoring. Nous consulterons les métriques enregistrées dans la console Firebase dans la suite de cet atelier de programmation.

9. Consulter les métriques dans la console Firebase

  1. Dans Logcat, cliquez sur l'URL de la console Firebase pour accéder à la page d'informations d'une trace. ceb9d5ba51bb6e89.jpeg

Vous pouvez également sélectionner le projet contenant votre application dans la console Firebase. Dans le panneau de gauche, recherchez l'option Publier et Surveiller, puis cliquez sur Performances.

  • Dans l'onglet principal Tableau de bord, faites défiler la page jusqu'au tableau des traces, puis cliquez sur l'onglet Traces personnalisées. Dans ce tableau, vous trouverez les traces de code personnalisé que nous avons ajoutées précédemment, ainsi que certaines traces prêtes à l'emploi, comme la trace _app_start.
  • Recherchez vos deux traces de code personnalisées, TestActivity-LoadTime et TestFragment-LoadTime. Cliquez sur la durée de l'une d'elles pour afficher plus de détails sur les données collectées.

a0d8455c5269a590.png

  1. La page d'informations de la trace de code personnalisé affiche des informations sur la durée de la trace (c'est-à-dire le temps de chargement mesuré).

5e92a307b7410d8b.png

  1. Vous pouvez également consulter les données sur les performances de votre trace d'écran personnalisée.
  • Revenez à l'onglet principal Tableau de bord, faites défiler la page vers le bas jusqu'au tableau des traces, puis cliquez sur l'onglet Rendu de l'écran. Dans ce tableau, vous trouverez les traces d'écran personnalisées que nous avons ajoutées précédemment, ainsi que les traces d'écran prêtes à l'emploi, telles que la trace MainActivity.
  • Recherchez votre trace d'écran personnalisée, MainActivity-TestFragment. Cliquez sur le nom de la trace pour afficher les données agrégées sur le rendu lent et les images figées.

ee7890c7e2c28740.png

10. Félicitations

Félicitations ! Vous avez mesuré le temps de chargement et les performances de rendu d'écran d'une activité et d'un fragment avec Firebase Performance Monitoring.

Ce que vous avez accompli

Étape suivante

Firebase Performance propose d'autres méthodes de mesure des performances de votre application que la traçabilité personnalisée. Il mesure automatiquement les données de performances de l'application au démarrage, en premier plan et en arrière-plan. Il est temps de vérifier ces métriques dans la console Firebase.

De plus, Firebase Performance propose une surveillance automatique des requêtes réseau HTTP/S. Vous pouvez ainsi facilement instrumenter les requêtes réseau sans écrire une seule ligne de code. Pouvez-vous essayer d'envoyer des requêtes réseau depuis votre application et trouver les métriques dans la console Firebase ?

Bonus

Maintenant que vous savez mesurer le temps de chargement et les performances de rendu de l'écran de votre activité/fragment à l'aide de traces de code personnalisées, pouvez-vous explorer notre base de code Open Source pour voir si vous pouvez capturer ces métriques prêtes à l'emploi pour toute activité/fragment faisant partie de l'application ? N'hésitez pas à envoyer le PR si vous le souhaitez. :-)

11. Formation bonus

Comprendre ce qui se passe lors du chargement d'une activité vous aidera à mieux comprendre les caractéristiques de performances de votre application. Dans une étape précédente, nous avons décrit de manière générale ce qui se passe lors du chargement d'une activité, mais le diagramme suivant décrit chaque phase de manière beaucoup plus détaillée.

cd61c1495fad7961.png