1. Introducción
Última actualización: 11/03/2021
¿Por qué debemos medir el rendimiento de las vistas?
Las vistas son una parte clave de las aplicaciones para Android que influyen directamente en la experiencia del usuario. Por ejemplo, tu actividad o fragmento contiene la IU que contiene los componentes de View con los que interactúan los usuarios. Los usuarios no pueden ver todo el contenido de la IU hasta que se dibuje por completo en la pantalla. Las pantallas lentas y congeladas afectarán directamente la interacción del usuario con la app y crearán una mala experiencia del 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 tu app (es decir, el tiempo de carga solo para la primera actividad) y el rendimiento de renderización de pantalla (es decir, fotogramas lentos y congelados para actividades, pero no para fragmentos). Sin embargo, las apps de la industria no suelen tener muchas actividades, sino más bien una actividad y varios fragmentos. Además, muchas apps suelen implementar sus propias vistas personalizadas para casos de uso más complejos. Por lo tanto, resulta útil comprender cómo medir el tiempo de carga y el rendimiento de renderización de la pantalla de actividades y fragmentos mediante la instrumentación de seguimientos de código personalizado en tu app. Puedes ampliar fácilmente este codelab para medir el rendimiento de los componentes de Custom View.
Qué aprenderás
- Cómo agregar Firebase Performance Monitoring a una app para Android
- Cómo comprender la carga de una actividad o un fragmento
- Cómo instrumentar seguimientos de código personalizado para medir el tiempo de carga de una actividad o un fragmento
- Información sobre la renderización de pantalla y qué es un fotograma lento o congelado
- Cómo instrumentar seguimientos de código personalizado con métricas para registrar pantallas lentas o inmovilizadas
- Cómo ver las métricas recopiladas en Firebase console
Requisitos
- Android Studio 4.0 o una versión posterior
- Un emulador o dispositivo Android
- Java 8 o superior
2. Cómo prepararte
Obtén el código
Ejecuta los siguientes comandos para clonar el código de muestra de este codelab. Esto creará una carpeta llamada codelab-measure-android-view-performance
en tu máquina:
$ git clone https://github.com/FirebaseExtended/codelab-measure-android-view-performance.git
$ cd codelab-measure-android-view-performance
Si no tienes Git en tu máquina, también puedes descargar el código directamente desde GitHub.
Importa el proyecto measure-view-performance-start
a Android Studio. Es probable que veas algunos errores de compilación o una advertencia sobre un archivo google-services.json
faltante. Lo corregiremos en la siguiente sección de este paso.
En este codelab, usaremos el complemento Firebase Assistant para registrar nuestra app para Android con un proyecto de Firebase y agregaremos los archivos de configuración, los complementos y las dependencias necesarios de Firebase a nuestro proyecto de Android, todo desde Android Studio.
Conecta tu app a Firebase
- Ve a Android Studio/Ayuda > Comprueba si hay actualizaciones para asegurarte de que estás usando las versiones más recientes de Android Studio y Firebase Assistant.
- Selecciona Herramientas > Firebase para abrir el panel de Assistant.
- Selecciona Performance Monitoring para agregarlo a tu app y, luego, haz clic en Comenzar a usar Performance Monitoring.
- Haz clic en Conectarse a Firebase para conectar el proyecto de Android con Firebase (se abrirá Firebase console en el navegador).
- En Firebase console, haz clic en Agregar proyecto y, luego, ingresa un nombre para el proyecto (si ya tienes uno, puedes seleccionarlo). Haz clic en Continuar y acepta las condiciones para crear el proyecto de Firebase y una nueva app de Firebase.
- A continuación, deberías ver un diálogo para Conectar la nueva app de Firebase a tu proyecto de Android Studio.
- En Android Studio, en el panel Assistant, deberías ver la confirmación de que tu app está conectada a Firebase.
Agrega Performance Monitoring a la app
En el panel Assistant de Android Studio, haz clic en Add Performance Monitoring to your app.
Verás un diálogo para Accept Changes después de la cual Android Studio deberá sincronizar tu app para garantizar que se hayan agregado todas las dependencias necesarias.
Por último, deberías ver el mensaje de éxito en el panel Assistant en Android Studio que indica que todas las dependencias están configuradas correctamente.
Como paso adicional, habilita el registro de depuración siguiendo las instrucciones del paso "Habilita el registro de depuración (opcional)". Las mismas instrucciones también están disponibles en la documentación pública.
3. Ejecuta la app
Si integraste correctamente tu app con el SDK de Performance Monitoring, ahora se debería compilar el proyecto. En Android Studio, haz clic en Run > Ejecuta "app" para compilar y ejecutar la app en tu emulador o dispositivo Android conectado.
La app tiene dos botones que te llevan a la Activity y Fragment correspondiente, de la siguiente manera:
En los siguientes pasos de este codelab, aprenderás a medir el tiempo de carga y el rendimiento de renderización de pantalla de tu actividad o fragmento.
4. Cómo comprender la carga de una actividad o un fragmento
En este paso, aprenderemos qué hace el sistema durante la carga de un objeto Activity o Fragment.
Información sobre la carga de una actividad
En el caso de una actividad, el tiempo de carga se define como el tiempo que transcurre desde que se crea el objeto de la actividad hasta que se dibuja por completo el Primer fotograma en la pantalla (es decir, cuando el usuario verá la IU completa de la actividad por primera vez). Para medir si tu app está completamente cargada, puedes usar el método reportFullyDrawn()
para medir el tiempo transcurrido entre el inicio de la app y la visualización completa de todos los recursos y las jerarquías de vistas.
En general, cuando tu app llama a 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 IU de la actividad en la pantalla.
Información sobre 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 host hasta que el Primer fotograma de la vista de fragmento se dibuja por completo en la pantalla.
5. Cómo medir el tiempo de carga de una actividad
Los retrasos en el primer fotograma pueden generar una mala experiencia del usuario, por lo que es importante que comprendas el retraso inicial de la carga que experimentan los usuarios. Puedes instrumentar un seguimiento de código personalizado para medir este tiempo de carga:
- Inicia el seguimiento de código personalizado (llamado
TestActivity-LoadTime
) en la clase Activity en cuanto 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");
// ...
}
- Anula la devolución de llamada
onCreate()
y obtén la vista que agregó el métodosetContentView()
.
@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);
// ...
}
- Incluimos una implementación de
FistDrawListener
, que tiene dos devoluciones de llamada:onDrawingStart()
yonDrawingFinish()
(consulta la siguiente sección a continuación para obtener más detalles sobreFirstDrawListener
y lo que puede afectar su rendimiento). Registra elFirstDrawListener
al final de la devolución de llamada deonCreate()
de Activity. Debes detener laviewLoadTrace
en la devolución de llamadaonDrawingFinish()
.
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();
}
});
- Vuelve a ejecutar la app. Luego, filtra el logcat con "Métrica de seguimiento de Logging". Presiona el botón
LOAD ACTIVITY
y busca registros como los siguientes:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)
🎉 ¡Felicitaciones! Mediste correctamente el tiempo de carga de una actividad y, luego, informaste esos datos a Firebase Performance Monitoring. Veremos la métrica registrada en Firebase console más adelante en este codelab.
Propósito de FirstDrawListener
En la sección anterior, registramos un FirstDrawListener
. El propósito de FirstDrawListener
es medir cuándo comenzó el primer fotograma y terminó de dibujarse.
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, une el resultado para proporcionar dos devoluciones de llamada de utilidad onDrawingStart()
y onDrawingFinish()
.
El código completo de FirstDrawListener
se puede encontrar en este código fuente de codelab.
6. Cómo medir el tiempo de carga de un fragmento
Medir el tiempo de carga de un objeto Fragment es similar a como lo medimos para una actividad, pero con algunas diferencias menores. Una vez más, instrumentaremos un seguimiento de código personalizado:
- Anula la devolución de llamada
onAttach()
y comienza a grabar tufragmentLoadTrace
. Le asignaremos el nombreTest-Fragment-LoadTime
a este seguimiento.
Como se explicó en un paso anterior, el objeto Fragment se puede crear en cualquier momento, pero solo se activa cuando está conectado 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");
}
- Registra el
FirstDrawListener
en la devolución de llamadaonViewCreated()
. Luego, al igual que en el ejemplo de la actividad, detén el seguimiento enonDrawingFinish()
.
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();
}
});
- Vuelve a ejecutar la app. Luego, filtra el logcat con "Métrica de seguimiento de Logging". Presiona el botón
LOAD FRAGMENT
y busca registros como los siguientes:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)
🎉 ¡Felicitaciones! Mediste correctamente el tiempo de carga de un fragmento y, luego, informaste esos datos a Firebase Performance Monitoring. Veremos la métrica registrada en Firebase console más adelante en este codelab.
7. Información sobre la renderización de pantalla y qué es un fotograma lento o congelado
La renderización de la IU consiste en generar un fotograma desde tu app y mostrarlo en la pantalla. Para garantizar que la interacción del usuario con tu app sea fluida, tu app debe renderizar los fotogramas en menos de 16 ms para lograr una velocidad de 60 fotogramas por segundo ( ¿Por qué 60 FPS?). Si tu app tiene una renderización de IU lenta, el sistema se verá obligado a omitir fotogramas, y el usuario notará un salto en tu app. Esto se denomina bloqueo.
Del mismo modo, los marcos congelados son fotogramas de la IU que tardan más de 700 ms en renderizarse. Esta demora es un problema, ya que tu app parece estar bloqueada y no responde a las entradas que realiza el usuario durante casi un segundo completo mientras se renderiza el fotograma.
8. Cómo medir los fotogramas lentos o congelados de un fragmento
Firebase Performance Monitoring captura automáticamente los fotogramas lentos o congelados de una actividad (pero solo si está acelerada por hardware). Sin embargo, esta función actualmente no está disponible para Fragments. Los fotogramas lentos o congelados de un fragmento se definen como los fotogramas lentos o congelados de toda la actividad entre las devoluciones de llamada de onFragmentAttached()
y onFragmentDetached()
en el ciclo de vida del fragmento.
Basándonos en la motivación de la clase AppStateMonitor
(que forma parte del SDK de Performance Monitoring responsable de registrar los seguimientos de pantalla de la actividad), implementamos la clase ScreenTrace
(que forma parte de este repositorio de código fuente del codelab). La clase ScreenTrace
se puede conectar a la devolución de llamada del ciclo de vida de FragmentManager
del objeto Activity para capturar fotogramas lentos o congelados. Esta clase proporciona dos APIs 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 los recuentos de fotogramas totales, congelados y lentos.
Si adjuntas estas métricas personalizadas, los seguimientos de pantalla de Fragments se pueden controlar de la misma manera que los seguimientos de pantalla de una actividad y se pueden mostrar junto con otros seguimientos de renderización de pantalla en el panel Rendimiento de Firebase console.
Para registrar seguimientos de pantalla de Fragment, sigue estos pasos:
- Inicializa la clase
ScreenTrace
en tu 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);
// ...
}
- Cuando cargues tu fragmento, regístrate en
FragmentLifecycleCallbacks
y anula las devoluciones de llamada deonFragmentAttached()
yonFragmentDetached()
. Ya lo hicimos por ti. Debes comenzar a registrar seguimientos de pantalla en la devolución de llamadaonFragmentAttached()
y detener el registro en la devolución de llamadaonFragmentDetached()
.
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);
}
};
- Vuelve a ejecutar la app. Luego, presiona el botón
LOAD FRAGMENT
. Espera unos segundos y, luego, haz clic en laback button
que aparece en la barra de navegación inferior.
Filtra el logcat con "Métrica de seguimiento de Logging" y, luego, busca registros como los siguientes:
I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)
Filtra el logcat con “FireperfViews” y, luego, busca registros como los siguientes:
D/FireperfViews: sendScreenTrace MainActivity-TestFragment, name: _st_MainActivity-TestFragment, total_frames: XX, slow_frames: XX, frozen_frames: XX
🎉 ¡Felicitaciones! Mediste correctamente los fotogramas lentos o congelados de un fragmento y, luego, informaste esos datos a Firebase Performance Monitoring. Veremos las métricas registradas en Firebase console más adelante en este codelab.
9. Verifica las métricas en Firebase console
- En logcat, haz clic en la URL de Firebase console para visitar la página de detalles del seguimiento.
De manera alternativa, en Firebase console, selecciona el proyecto que tiene tu app. En el panel izquierdo, busca la carpeta Versión y Supervisar y, luego, haz clic en Rendimiento.
- En la pestaña principal Panel, desplázate hacia abajo hasta la tabla de seguimientos y haz clic en la pestaña Seguimientos personalizados. En esta tabla, verás los seguimientos de código personalizado que agregamos antes, además de algunos seguimientos listos para usar, como el seguimiento
_app_start
. - Encuentra tus dos seguimientos de código personalizado,
TestActivity-LoadTime
yTestFragment-LoadTime
. Haz clic en la Duración de cualquiera de los dos para ver más detalles sobre los datos recopilados.
- En la página de detalles del seguimiento de código personalizado, se muestra información sobre la duración del seguimiento (es decir, el tiempo de carga medido).
- También puedes ver los datos de rendimiento de tu seguimiento de pantalla personalizado.
- Regresa a la pestaña principal Panel, desplázate hacia abajo hasta la tabla de seguimientos y haz clic en la pestaña Renderización de pantalla. En esta tabla, verás los seguimientos de pantalla personalizados que agregamos antes, además de los seguimientos de pantalla listos para usar, como el seguimiento
MainActivity
. - Busca tu seguimiento de pantalla personalizado,
MainActivity-TestFragment
. Haz clic en el nombre del seguimiento para ver los datos agregados de renderización lenta y fotogramas congelados.
10. Felicitaciones
¡Felicitaciones! Mediste correctamente el tiempo de carga y el rendimiento de renderización de pantalla de una actividad y un fragmento con Firebase Performance Monitoring.
Qué lograste
- Integraste Firebase Performance Monitoring en una app de ejemplo.
- Ahora conoces el ciclo de vida de la carga de vistas
- Mediste el tiempo de carga de una actividad y un fragmento agregando seguimientos de código personalizado.
- Registraste fotogramas lentos o congelados agregando seguimientos de pantalla personalizados con métricas personalizadas.
¿Qué sigue?
Además del seguimiento personalizado, Firebase Performance ofrece más formas de medir el rendimiento de tu app. Mide automáticamente el tiempo de inicio de la app, los datos de rendimiento de la app en primer plano y en segundo plano. Es momento de que revises estas métricas en Firebase console.
Además, Firebase Performance ofrece supervisión automática de solicitudes de red HTTP/S. De este modo, puedes instrumentar con facilidad las solicitudes de red sin escribir ni una sola línea de código. ¿Puedes intentar enviar algunas solicitudes de red desde tu app y encontrar las métricas en Firebase console?
Contenido adicional
Ahora que sabes cómo medir el tiempo de carga y el rendimiento de renderización de pantalla de tu actividad o fragmento con seguimientos de código personalizado, ¿puedes explorar nuestra base de código de código abierto para ver si puedes capturar esas métricas de inmediato para cualquier actividad o fragmento que forme parte de la app? Si lo deseas, puedes enviar el PR :-)
11. Aprendizaje adicional
Comprender lo que sucede durante la carga de una actividad te ayudará a comprender mejor las características de rendimiento de tu app. En un paso anterior, describimos a grandes rasgos lo que sucede durante la carga de una actividad, pero en el siguiente diagrama se describe cada fase con mucho más detalle.