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'UI qui contient les composants View avec lesquels les utilisateurs interagissent. Les utilisateurs ne peuvent pas voir l'intégralité du contenu de l'UI 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, comme 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 d'écran (c'est-à-dire les frames lents et figés pour les activités, mais pas pour les fragments). Toutefois, les applications sectorielles ne comportent généralement pas beaucoup d'activités, mais plutôt une activité et plusieurs fragments. De plus, de nombreuses applications implémentent généralement leurs propres vues personnalisées pour les 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 de vue personnalisés.

Points abordés

  • Ajouter Firebase Performance Monitoring à une application Android
  • Comprendre le chargement d'une activité ou d'un fragment
  • Instrumenter des traces de code personnalisé pour mesurer le temps de chargement d'une activité ou d'un fragment
  • Comprendre le rendu d'écran et ce qu'est un frame lent/figé
  • Instrumenter des traces de code personnalisé 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 version 4.0 ou 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. Un dossier nommé codelab-measure-android-view-performance sera créé sur votre machine :

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

Si vous n'avez pas git sur votre ordinateur, 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 peut-être un avertissement concernant un fichier google-services.json manquant. Nous corrigerons cela 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, plug-ins et dépendances Firebase nécessaires à notre projet Android, le tout depuis Android Studio !

Associer votre application à Firebase

  1. Accédez à Android Studio/Aide > Rechercher les mises à jour pour vous assurer d'utiliser 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
  3. Sélectionnez Performance Monitoring pour l'ajouter à votre application, puis cliquez sur Premiers pas avec Performance Monitoring.
  4. Cliquez sur le bouton pour créer un projet, puis saisissez un nom (par exemple, Measure Performance Codelab).
  5. Cliquez sur Continuer.
  6. Si vous y êtes invité, lisez et acceptez les Conditions d'utilisation de Firebase, puis cliquez sur Continuer.
  7. (Facultatif) Activez l'assistance IA dans la console Firebase (appelée "Gemini dans Firebase").
  8. Pour cet atelier de programmation, vous n'avez pas besoin de Google Analytics. Désactivez donc l'option Google Analytics.
  9. Vous devriez ensuite voir une boîte de dialogue vous invitant à associer votre nouvelle application Firebase à votre projet Android Studio.
    42c498d28ead2b77.png
  10. 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 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 confirmation devrait s'afficher dans le volet Assistant d'Android Studio, indiquant que toutes les dépendances sont correctement configurées.

aa0d46fc944e0c0b.png

En complément, activez la journalisation du débogage en suivant les instructions de l'étape "(Facultatif) Activer la journalisation du 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 > Run 'app' (Exécuter > Exécuter "app") pour compiler et exécuter l'application sur votre appareil Android/émulateur connecté.

L'application comporte deux boutons qui vous redirigent vers 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 d'affichage de l'écran de votre activité ou fragment.

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

Dans cette étape, nous allons découvrir ce que fait le système lors du 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 moment où le premier frame est complètement dessiné à l'écran (c'est à ce moment-là que votre utilisateur verra l'UI complète de l'activité pour la première fois). Pour mesurer si votre application est entièrement dessinée, vous pouvez utiliser la méthode reportFullyDrawn() pour mesurer le temps écoulé entre le lancement de l'application et l'affichage complet de toutes les ressources et hiérarchies de vues.

En règle 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 à la durée entre la création de l'activité et le moment où l'utilisateur voit l'UI de l'activité sur son écran.

c20d14b151549937.png

Comprendre le chargement d'un fragment

Comme pour l'activité, le temps de chargement d'un fragment est défini comme le temps écoulé entre le moment où le fragment est associé à son activité hôte et le moment où le premier frame de la vue du fragment est entièrement dessiné à l'écran.

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

Les retards dans le premier frame peuvent nuire à l'expérience utilisateur. Il est donc important de comprendre le temps de chargement initial que vos utilisateurs rencontrent. Vous pouvez instrumenter une trace de code personnalisée pour mesurer ce temps de chargement :

  1. Démarrez la trace de code personnalisé (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. Remplacez 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() (consultez la section suivante pour en savoir plus sur FirstDrawListener et ce qui peut affecter ses performances). Enregistrez 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. Exécutez à nouveau l'application, puis filtrez le logcat avec Logging trace metric (Enregistrement de la métrique de trace). Appuyez sur le bouton LOAD ACTIVITY et recherchez des journaux semblables à ceux ci-dessous :
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Félicitations ! Vous avez réussi à mesurer le temps de chargement d'une activité et à envoyer ces données à Firebase Performance Monitoring. Nous examinerons la métrique enregistrée dans la console Firebase plus loin dans cet atelier de programmation.

Objectif de FirstDrawListener

Dans la section ci-dessus, nous avons enregistré un FirstDrawListener. L'objectif de FirstDrawListener est de mesurer le moment où la première frame a commencé et fini d'être dessinée.

Il implémente ViewTreeObserver.OnDrawListener et remplace le rappel onDraw() qui est appelé lorsque l'arborescence de vues 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 est disponible 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 similaire à celle d'une activité, mais avec quelques différences mineures. Encore une fois, nous allons instrumenter une trace de code personnalisée :

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

Comme expliqué dans une étape précédente, 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 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. Exécutez à nouveau l'application, puis filtrez le logcat avec Logging trace metric (Enregistrement de la métrique de trace). Appuyez sur le bouton LOAD FRAGMENT et recherchez des journaux semblables à ceux ci-dessous :
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Félicitations ! Vous avez réussi à mesurer le temps de chargement d'un fragment et à signaler ces données à Firebase Performance Monitoring. Nous examinerons la métrique enregistrée dans la console Firebase plus loin dans cet atelier de programmation.

7. Comprendre le rendu d'écran et ce qu'est un frame lent/figé

L'affichage de l'UI est une action qui consiste à générer une frame à partir de votre application et à l'afficher à l'écran. Pour garantir une interaction fluide entre l'utilisateur et votre application, elle doit afficher des images en moins de 16 ms pour obtenir 60 images par seconde ( pourquoi 60 fps ?). Si votre application présente un problème d'affichage lent de l'UI, le système est obligé de sauter des images, de telle sorte que l'utilisateur constate un rendu saccadé dans votre application. On parle d'à-coups.

De même, les images figées sont des images de l'UI 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 cadre est en train de s'afficher.

8. Mesurer les images lentes/figées d'un fragment

Firebase Performance Monitoring capture automatiquement les frames lents/figés pour une activité (mais uniquement si elle est accélérée par le matériel). Toutefois, cette fonctionnalité n'est actuellement pas disponible pour les fragments. Les frames lents/figés d'un fragment sont définis comme les frames lents/figés pour l'ensemble de l'activité entre les rappels onFragmentAttached() et onFragmentDetached() dans le cycle de vie du fragment.

En nous inspirant de la classe AppStateMonitor (qui fait partie du SDK Performance Monitoring et qui est 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 de code source de cet atelier de programmation). La classe ScreenTrace peut être associée au rappel de cycle de vie FragmentManager de l'activité pour capturer les frames lents/figés. Cette classe fournit deux API publiques :

  • recordScreenTrace() : démarre l'enregistrement d'une trace d'écran.
  • sendScreenTrace() : arrête l'enregistrement d'une trace d'écran et associe des métriques personnalisées pour enregistrer le nombre total d'images, ainsi que le nombre d'images lentes et figées.

En associant ces métriques personnalisées, les traces d'écran pour les fragments peuvent être traitées de la même manière que les traces d'écran pour 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 pour 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 les 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, puis appuyez 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 trace de journalisation), puis recherchez des journaux comme ceux ci-dessous :

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

Filtrez Logcat avec "FireperfViews", puis recherchez des journaux semblables à ceux ci-dessous :

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

🎉 Félicitations ! Vous avez réussi à mesurer les frames lents/figés pour un fragment et à signaler ces données à Firebase Performance Monitoring. Nous examinerons les métriques enregistrées dans la console Firebase plus loin dans cet atelier de programmation.

9. Consulter les métriques dans la console Firebase

  1. Dans le 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 la section Release & Monitor (Lancement et surveillance), puis cliquez sur Performance (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 verrez les traces de code personnalisé que nous avons ajoutées précédemment, ainsi que des traces prêtes à l'emploi, comme la trace _app_start.
  • Recherchez vos deux traces de code personnalisé, TestActivity-LoadTime et TestFragment-LoadTime. Cliquez sur la durée de l'un ou l'autre pour afficher plus de détails sur les données collectées.

a0d8455c5269a590.png

  1. La page d'informations sur 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 afficher 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 jusqu'au tableau des traces, puis cliquez sur l'onglet Rendu de l'écran. Dans ce tableau, vous verrez les traces d'écran personnalisées que nous avons ajoutées précédemment, ainsi que les traces d'écran prêtes à l'emploi, comme 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 des frames lents et figés.

ee7890c7e2c28740.png

10. Félicitations

Félicitations ! Vous avez réussi à mesurer le temps de chargement et les performances de rendu d'écran d'une activité et d'un fragment à l'aide de Firebase Performance Monitoring.

Ce que vous avez accompli

Étape suivante

Firebase Performance offre plus de façons de mesurer les performances de votre application que le traçage personnalisé. Il mesure automatiquement les données de performances concernant le temps de démarrage de l'application, l'application au premier plan et l'application en arrière-plan. Il est temps de vérifier ces métriques dans la console Firebase.

Firebase Performance propose également la surveillance automatique des requêtes réseau HTTP/S. Vous pouvez ainsi instrumenter facilement 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 de trouver les métriques dans la console Firebase ?

Bonus

Maintenant que vous savez comment mesurer le temps de chargement et les performances de rendu d'é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é/tout fragment faisant partie de l'application ? N'hésitez pas à envoyer la demande de pull si vous le souhaitez :-)

11. Apprentissage 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 beaucoup plus en détail.

cd61c1495fad7961.png