Mide el tiempo de carga y la visualización de la pantalla con Firebase Performance Monitoring

1. Introducción

Última actualización: 2021-03-11

¿Por qué necesitamos medir el rendimiento de las Vistas?

Las vistas son una parte clave de las aplicaciones de Android que afectan directamente la experiencia del usuario. Por ejemplo, su Actividad o Fragmento contiene la interfaz de usuario que contiene los componentes de Vista con los que interactúan los usuarios. Los usuarios no pueden ver todo el contenido de la interfaz de usuario hasta que esté completamente dibujado en la pantalla. Las pantallas lentas y congeladas afectarán directamente la interacción del usuario con su aplicación y crearán una mala experiencia para el usuario.

¿Firebase Performance Monitoring no proporciona estas métricas de rendimiento listas para usar?

Firebase Performance Monitoring captura automáticamente algunos datos de rendimiento listos para usar, como la hora de inicio de su aplicación (es decir, el tiempo de carga solo para su primera actividad) y el rendimiento de la visualización de la pantalla (es decir, marcos lentos y congelados para actividades pero no para Fragmentos). Sin embargo, las aplicaciones de la industria generalmente no tienen muchas actividades, sino una actividad y varios fragmentos. Además, muchas aplicaciones suelen implementar sus propias vistas personalizadas para casos de uso más complejos. Por lo tanto, a menudo es útil comprender cómo medir el tiempo de carga y el rendimiento de representación de la pantalla tanto de Actividades como de Fragmentos mediante la instrumentación de seguimientos de código personalizados en su aplicación. Puede ampliar fácilmente este laboratorio de código para medir el rendimiento de los componentes de vista personalizada.

lo que aprenderás

  • Cómo agregar Firebase Performance Monitoring a una aplicación de Android
  • Entendiendo la carga de una Actividad o un Fragmento
  • Cómo instrumentar seguimientos de código personalizados para medir el tiempo de carga de una Actividad o Fragmento
  • Comprensión de la representación de pantalla y qué es un cuadro lento/congelado
  • Cómo instrumentar seguimientos de código personalizados con métricas para registrar pantallas lentas/congeladas
  • Cómo ver las métricas recopiladas en Firebase console

Lo que necesitarás

  • Android Studio 4.0 o superior
  • Un dispositivo/emulador de Android
  • Java versión 8 o superior

2. Preparación

Obtener el código

Ejecute los siguientes comandos para clonar el código de muestra para este codelab. Esto creará una carpeta llamada codelab-measure-android-view-performance en su máquina:

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

Si no tiene git en su máquina, también puede descargar el código directamente desde GitHub.

Importe el proyecto measure-view-performance-start en Android Studio. Probablemente verá algunos errores de compilación o tal vez una advertencia sobre la falta de un archivo google-services.json . Corregiremos esto en la siguiente sección de este paso.

En este laboratorio de código, usaremos el complemento Firebase Assistant para registrar nuestra aplicación de Android con un proyecto de Firebase y agregar los archivos de configuración, los complementos y las dependencias necesarios de Firebase a nuestro proyecto de Android, ¡ todo desde Android Studio !

Conecta tu aplicación a Firebase

  1. Vaya a Android Studio / Ayuda > Buscar actualizaciones para asegurarse de que está utilizando las últimas versiones de Android Studio y Firebase Assistant.
  2. Seleccione Herramientas > Firebase para abrir el panel Asistente .

e791cama0999db1e0.png

  1. Elija Performance Monitoring para agregar a su aplicación, luego haga clic en Comenzar con Performance Monitoring .
  2. Haga clic en Conectar a Firebase para conectar su proyecto de Android con Firebase (esto abrirá la consola de Firebase en su navegador) .
  3. En la consola de Firebase, haga clic en Agregar proyecto , luego ingrese un nombre de proyecto de Firebase (si ya tiene un proyecto de Firebase, puede seleccionar ese proyecto existente en su lugar) . Haga clic en Continuar y acepte los términos para crear el proyecto de Firebase y una nueva aplicación de Firebase.
  4. A continuación, debería ver un cuadro de diálogo para conectar su nueva aplicación Firebase a su proyecto de Android Studio.

42c498d28ead2b77.png

  1. De vuelta en Android Studio, en el panel Asistente , debería ver la confirmación de que su aplicación está conectada a Firebase.

dda8bdd9488167a0.png

Agregue Monitoreo de rendimiento a su aplicación

En el panel Asistente en Android Studio, haga clic en Agregar monitoreo de rendimiento a su aplicación .

Debería ver un cuadro de diálogo para Aceptar cambios , luego de lo cual Android Studio debería sincronizar su aplicación para asegurarse de que se hayan agregado todas las dependencias necesarias.

9b58145acc4be030.png

Finalmente, debería ver el mensaje de éxito en el panel Asistente en Android Studio que indica que todas las dependencias están configuradas correctamente.

aa0d46fc944e0c0b.png

Como paso adicional, habilite el registro de depuración siguiendo las instrucciones del paso "(Opcional) Habilitar el registro de depuración". Las mismas instrucciones también están disponibles en la documentación pública .

3. Ejecute la aplicación

Si ha integrado correctamente su aplicación con el SDK de supervisión del rendimiento, el proyecto ahora debería compilarse. En Android Studio, haga clic en Ejecutar > Ejecutar 'aplicación' para compilar y ejecutar la aplicación en su dispositivo/emulador Android conectado.

La aplicación tiene dos botones que lo llevan a la Actividad y al Fragmento correspondientes, como este:

410d8686b4f45c33.png

En los siguientes pasos de este laboratorio de código, aprenderá a medir el tiempo de carga y el rendimiento de representación en pantalla de su Actividad o Fragmento.

4. Entendiendo la carga de una Actividad o Fragmento

En este paso, aprenderemos qué está haciendo el sistema durante la carga de una Actividad o Fragmento.

Comprender la carga de una actividad

Para una actividad, el tiempo de carga se define como el tiempo que comienza desde que se crea el objeto de la actividad hasta que el primer cuadro se dibuja por completo en la pantalla ( aquí es cuando el usuario verá la interfaz de usuario completa de la actividad por primera vez). tiempo ). Para medir si su aplicación está completamente dibujada, puede usar el método reportFullyDrawn() para medir el tiempo transcurrido entre el inicio de la aplicación y la visualización completa de todos los recursos y ver las jerarquías.

En un nivel alto, cuando su aplicación llama startActivity(Intent) , el sistema realiza automáticamente los siguientes procesos. Cada proceso tarda en completarse, lo que se suma al tiempo que transcurre entre la creación de la actividad y el momento en que el usuario ve la interfaz de usuario de la actividad en su pantalla.

c20d14b151549937.png

Entendiendo la carga de un Fragmento

De manera similar a la Actividad, el tiempo de carga de un Fragmento se define como el tiempo que comienza desde que el Fragmento se adjunta a su Actividad anfitriona hasta que el Primer Cuadro de la Vista del Fragmento se dibuja por completo en la pantalla.

5. Medir el tiempo de carga de una Actividad

Los retrasos en el primer cuadro pueden generar una mala experiencia para el usuario, por lo que es importante comprender cuánto retraso de carga inicial experimentan los usuarios. Puede instrumentar un seguimiento de código personalizado para medir este tiempo de carga:

  1. Inicie el seguimiento del código personalizado (denominado TestActivity-LoadTime ) en la clase Activity tan pronto como se cree el objeto Activity.

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. Anule la devolución de llamada onCreate() y obtenga la Vista agregada por el método 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. Hemos incluido una implementación de FistDrawListener , que tiene dos devoluciones de llamada: onDrawingStart() y onDrawingFinish() (consulte la siguiente sección a continuación para obtener más detalles sobre FirstDrawListener y lo que puede afectar su rendimiento) . Registre FirstDrawListener al final de la devolución de llamada onCreate() de Activity. Debe detener su viewLoadTrace en la devolución de llamada 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. Vuelva a ejecutar la aplicación. Luego, filtre el logcat con " Logging trace metric ". Toque el botón LOAD ACTIVITY y busque registros como los siguientes:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 ¡Felicidades! Midió con éxito el tiempo de carga de una actividad y reportó esos datos a Firebase Performance Monitoring. Veremos la métrica registrada en la consola de Firebase más adelante en este laboratorio de código.

Propósito de FirstDrawListener

En la sección anterior, registramos un FirstDrawListener . El propósito de FirstDrawListener es medir cuándo el primer cuadro ha comenzado y terminado el dibujo.

Implementa ViewTreeObserver.OnDrawListener y anula la devolución de llamada onDraw() que se invoca cuando el árbol de vistas está a punto de dibujarse. Luego envuelve el resultado para proporcionar dos devoluciones de llamada de utilidad onDrawingStart() y onDrawingFinish() .

El código completo de FirstDrawListener se puede encontrar en el código fuente de este codelab .

6. Medir el tiempo de carga de un Fragmento

Medir el tiempo de carga de un Fragmento es similar a cómo lo medimos para una Actividad pero con algunas diferencias menores. Nuevamente, instrumentaremos un seguimiento de código personalizado :

  1. Anule la devolución de llamada onAttach() y comience a grabar su fragmentLoadTrace . Llamaremos a este seguimiento Test-Fragment-LoadTime .

Como se explicó en un paso anterior, el objeto Fragment se puede crear en cualquier momento, pero solo se activa cuando se adjunta a su actividad host.

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. Registre FirstDrawListener en la devolución de llamada onViewCreated() . Luego, de manera similar al ejemplo de Actividad, detenga el seguimiento en 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. Vuelva a ejecutar la aplicación. Luego, filtre el logcat con " Logging trace metric ". Toque el botón LOAD FRAGMENT y busque registros como los siguientes:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 ¡Felicidades! Midió con éxito el tiempo de carga de un Fragmento y reportó esos datos a Firebase Performance Monitoring. Veremos la métrica registrada en la consola de Firebase más adelante en este laboratorio de código.

7. Comprensión de la representación de pantalla y qué es un cuadro lento/congelado

La representación de la interfaz de usuario es el acto de generar un marco desde su aplicación y mostrarlo en la pantalla. Para garantizar que la interacción de un usuario con su aplicación sea fluida, su aplicación debe generar cuadros en menos de 16 ms para lograr 60 cuadros por segundo ( ¿por qué 60 fps? ). Si su aplicación sufre una representación lenta de la interfaz de usuario, entonces el sistema se ve obligado a omitir fotogramas y el usuario percibirá tartamudeos en su aplicación. A esto lo llamamos jank .

Del mismo modo, los fotogramas congelados son fotogramas de la interfaz de usuario que tardan más de 700 ms en procesarse. Este retraso es un problema porque su aplicación parece estar atascada y no responde a la entrada del usuario durante casi un segundo completo mientras se procesa el marco.

8. Medir los fotogramas lentos/congelados de un fragmento

Firebase Performance Monitoring captura automáticamente fotogramas lentos/congelados para una actividad ( pero solo si está acelerada por hardware ). Sin embargo, esta característica no está disponible actualmente para Fragmentos. Los fotogramas lentos/congelados de un Fragmento se definen como los fotogramas lentos/congelados de toda la Actividad entre las devoluciones de llamada onFragmentAttached() y onFragmentDetached() en el ciclo de vida del Fragmento.

Tomando la motivación de la clase AppStateMonitor ( que es parte del SDK de monitoreo de rendimiento responsable de registrar los seguimientos de pantalla para la actividad ), implementamos la clase ScreenTrace ( que es parte de este repositorio de código fuente de codelab ). La clase ScreenTrace se puede conectar a la devolución de llamada del ciclo de vida del FragmentManager de la actividad para capturar fotogramas lentos/congelados. Esta clase proporciona dos API públicas:

  • recordScreenTrace() : Comienza a grabar un seguimiento de pantalla
  • sendScreenTrace() : detiene la grabación de un seguimiento de pantalla y adjunta métricas personalizadas para registrar recuentos de fotogramas totales, lentos y congelados

Al adjuntar estas métricas personalizadas, los seguimientos de pantalla para fragmentos se pueden manejar de la misma manera que los seguimientos de pantalla para una actividad y se pueden mostrar junto con otros seguimientos de representación de pantalla en el panel de rendimiento de Firebase console.

Así es como se registran los rastros de pantalla para su Fragmento:

  1. Inicialice la clase ScreenTrace en su Actividad que aloja el Fragmento.

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. Cuando cargue su fragmento, regístrese en FragmentLifecycleCallbacks y anule las devoluciones de llamada onFragmentAttached() y onFragmentDetached() . Hemos hecho esto por ti. Debe comenzar a grabar los rastros de la pantalla en la devolución de llamada onFragmentAttached() y detener la grabación en la devolución de llamada 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. Vuelva a ejecutar la aplicación. Luego, toque el botón LOAD FRAGMENT . Espere unos segundos, luego haga clic en el back button en la barra de navegación inferior.

Filtre el logcat con " Logging trace metric ", luego busque registros como los siguientes:

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

Filtre el logcat con " FireperfViews ", luego busque registros como los siguientes:

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

🎉 ¡Felicidades! Mediste correctamente los fotogramas lentos/congelados de un fragmento y reportaste esos datos a Firebase Performance Monitoring. Veremos las métricas registradas en la consola de Firebase más adelante en este laboratorio de código.

9. Verifique las métricas en la consola de Firebase

  1. En el logcat, haga clic en la URL de la consola de Firebase para visitar la página de detalles para realizar un seguimiento. ceb9d5ba51bb6e89.jpeg

Alternativamente, en la consola de Firebase , seleccione el proyecto que tiene su aplicación. En el panel izquierdo, ubique la sección Lanzamiento y monitoreo , luego haga clic en Rendimiento .

  • En la pestaña principal del Tablero , desplácese hacia abajo hasta la tabla de seguimientos, luego haga clic en la pestaña Seguimientos personalizados . En esta tabla, verá los seguimientos del código personalizado que agregamos anteriormente, además de algunos seguimientos listos para usar , como el seguimiento _app_start .
  • Encuentre sus dos seguimientos de código personalizados, TestActivity-LoadTime y TestFragment-LoadTime . Haga clic en Duración para cualquiera de los dos para ver más detalles sobre los datos recopilados.

a0d8455c5269a590.png

  1. La página de detalles del seguimiento del código personalizado muestra información sobre la duración del seguimiento (es decir, el tiempo de carga medido).

5e92a307b7410d8b.png

  1. También puede ver los datos de rendimiento de su seguimiento de pantalla personalizado.
  • Vuelva a la pestaña principal del Tablero , desplácese hacia abajo hasta la tabla de seguimientos y luego haga clic en la pestaña Representación de pantalla . En esta tabla, verá los seguimientos de pantalla personalizados que agregamos anteriormente, además de cualquier seguimiento de pantalla listo para usar , como el seguimiento de MainActivity .
  • Encuentre su seguimiento de pantalla personalizado, MainActivity-TestFragment . Haga clic en el nombre de la traza para ver los datos agregados de procesamiento lento y fotogramas congelados.

ee7890c7e2c28740.png

10. Felicitaciones

¡Felicidades! Ha medido con éxito el tiempo de carga y el rendimiento de representación de pantalla de una Actividad y un Fragmento mediante Firebase Performance Monitoring.

lo que has logrado

Que sigue

Firebase Performance ofrece más formas de medir el rendimiento de su aplicación además del seguimiento personalizado. Mide automáticamente el tiempo de inicio de la aplicación, la aplicación en primer plano y los datos de rendimiento de la aplicación en segundo plano . Es hora de que verifiques estas métricas en Firebase Console .

Además, Firebase Performance ofrece monitoreo automático de solicitudes de red HTTP/S . Con eso, puede instrumentar fácilmente las solicitudes de red sin escribir una sola línea de código. ¿Puede intentar enviar algunas solicitudes de red desde su aplicación y encontrar las métricas en la consola de Firebase ?

Prima

Ahora que sabe cómo medir el tiempo de carga y el rendimiento de representación de pantalla de su Actividad/Fragmento mediante el uso de seguimientos de código personalizados, ¿puede explorar nuestra base de código de fuente abierta para ver si puede capturar esas métricas listas para usar para cualquier Actividad/Fragmento? eso es parte de la aplicación? Siéntase libre de enviar el PR si lo desea :-)

11. Aprendizaje adicional

Comprender lo que sucede durante la carga de una actividad lo ayudará a comprender mejor las características de rendimiento de su aplicación. En un paso anterior, describimos en un alto nivel lo que sucede durante la carga de una actividad, pero el siguiente diagrama describe cada fase con mucho más detalle.

cd61c1495fad7961.png