Medir o tempo de carregamento e a renderização da tela com o Monitoramento de desempenho do Firebase

1. Introdução

Última atualização:11/03/2021

Por que precisamos medir a performance das visualizações?

As visualizações são uma parte fundamental dos apps Android e afetam diretamente a experiência do usuário. Por exemplo, a atividade ou o fragmento contém a interface que contém os componentes de visualização com que os usuários interagem. Os usuários não conseguem ver todo o conteúdo da interface até que ele seja completamente desenhado na tela. Telas lentas e congeladas prejudicam diretamente a interação do usuário com o app e criam uma experiência ruim para o usuário.

O Monitoramento de desempenho do Firebase não oferece essas métricas de desempenho prontas para uso?

O Monitoramento de desempenho do Firebase captura automaticamente alguns dados de desempenho prontos para uso, como o horário de início do app (apenas o tempo de carregamento da primeira atividade) e o desempenho da renderização de tela (ou seja, frames lentos e congelados para atividades, mas não para fragmentos). No entanto, os apps do setor geralmente não têm muitas atividades, mas uma e vários fragmentos. Além disso, muitos apps geralmente implementam as próprias visualizações personalizadas para casos de uso mais complexos. Por isso, geralmente é útil entender como medir o tempo de carregamento e o desempenho da renderização de tela de atividades e fragmentos instrumentando traces de código personalizados no app. Este codelab pode ser facilmente estendido para medir o desempenho dos componentes de visualização personalizada.

O que você aprenderá

  • Como adicionar o Monitoramento de desempenho do Firebase a um app Android
  • Noções básicas sobre o carregamento de uma atividade ou um fragmento
  • Como instrumentar traces de código personalizados para medir o tempo de carregamento de uma atividade ou um fragmento.
  • Compreensão da renderização de tela e o que é um frame lento/congelado
  • Como instrumentar traces de código personalizados com métricas para gravar telas lentas/congeladas
  • Como visualizar as métricas coletadas no Console do Firebase

O que é necessário

  • Android Studio 4.0 ou mais recente.
  • Um dispositivo/emulador Android
  • Java versão 8 ou mais recente

2. Etapas da configuração

Buscar o código

Execute os comandos abaixo para clonar o exemplo de código para este codelab. Isso criará uma pasta chamada codelab-measure-android-view-performance na sua máquina:

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

Caso você não tenha o git na sua máquina, também é possível fazer o download do código diretamente no GitHub.

Importe o projeto measure-view-performance-start para o Android Studio. Você provavelmente vai encontrar alguns erros de compilação ou um aviso sobre um arquivo google-services.json ausente. Vamos corrigir isso na próxima seção desta etapa.

Neste codelab, vamos usar o plug-in do Firebase Assistente para registrar nosso app Android com um projeto do Firebase e adicionar os arquivos de configuração, plug-ins e dependências necessários ao nosso projeto Android. Tudo isso no Android Studio.

Conectar seu app ao Firebase

  1. Acesse Android Studio/Help > Verifique se há atualizações para confirmar se você está usando as versões mais recentes do Android Studio e do Firebase Assistente.
  2. Selecione Ferramentas > Firebase para abrir o painel do Assistente.

e791bed0999db1e0.png.

  1. Escolha Monitoramento de desempenho para adicionar ao seu app e clique em Começar a usar o Monitoramento de desempenho.
  2. Clique em Conectar ao Firebase para conectar seu projeto do Android ao Firebase (isso abrirá o console do Firebase no seu navegador).
  3. No Console do Firebase, clique em Adicionar projeto e digite o nome de um projeto do Firebase (se você já tiver um projeto do Firebase, selecione-o). Clique em Continuar e aceite os termos para criar o projeto e um novo app do Firebase.
  4. Em seguida, você verá uma caixa de diálogo para Conectar o novo app Firebase ao projeto do Android Studio.

42c498d28ead2b77.png

  1. No painel Assistente do Android Studio, você verá a confirmação de que o app está conectado ao Firebase.

dda8bdd9488167a0.png

Adicionar o Monitoramento de desempenho ao app

No painel Assistente do Android Studio, clique em Adicionar o Monitoramento de desempenho ao seu app.

Uma caixa de diálogo Accept Changes vai aparecer. Depois disso, o Android Studio vai sincronizar o app para garantir que todas as dependências necessárias tenham sido adicionadas.

9b58145acc4be030.png.

Por fim, você vai encontrar a mensagem de êxito no painel do Assistente no Android Studio informando que todas as dependências estão configuradas corretamente.

aa0d46fc944e0c0b.png

Como etapa adicional, ative a geração de registros de depuração seguindo as instruções na etapa "(Opcional) Ativar a geração de registros de depuração". As mesmas instruções também estão disponíveis na documentação pública.

3. Execute o aplicativo

Se você integrou seu app ao SDK do Monitoramento de desempenho, o projeto será compilado. No Android Studio, clique em Run > Execute "app" para criar e executar o app no dispositivo/emulador Android conectado.

O app tem dois botões que levam a uma atividade e um fragmento correspondentes, desta forma:

410d8686b4f45c33.png

Nas etapas a seguir deste codelab, você vai aprender a medir o tempo de carregamento e o desempenho da renderização de tela da sua atividade ou fragmento.

4. Noções básicas sobre o carregamento de uma atividade ou um fragmento

Nesta etapa, vamos aprender o que o sistema está fazendo durante o carregamento de uma atividade ou um fragmento.

Noções básicas sobre o carregamento de uma atividade

Para uma atividade, o tempo de carregamento é definido como o tempo que começa quando o objeto da atividade é criado até o primeiro quadro ser completamente desenhado na tela. quando o usuário verá a interface completa da atividade pela primeira vez. Para saber se o app está totalmente renderizado, use o método reportFullyDrawn() e confira o tempo decorrido entre a inicialização do app e a exibição completa de todos os recursos e das hierarquias de visualização.

Em um nível alto, quando o app chama startActivity(Intent), o sistema executa automaticamente os seguintes processos. Cada processo leva tempo para ser concluído, o que aumenta o tempo entre a criação da atividade e quando o usuário vê a interface da atividade na tela.

c20d14b151549937.png

Noções básicas sobre o carregamento de um fragmento

Semelhante à atividade, o tempo de carregamento de um fragmento é definido como o momento em que o fragmento é anexado à atividade host até que o primeiro frame da visualização de fragmento seja completamente desenhado na tela.

5. Medir o tempo de carregamento de uma atividade

Como os atrasos no primeiro frame podem atrapalhar a experiência do usuário, é importante entender o atraso no carregamento inicial. É possível instrumentar um trace de código personalizado para medir esse tempo de carregamento:

  1. Inicie o trace de código personalizado (chamado TestActivity-LoadTime) na classe Activity assim que o objeto Activity for criado.

TestActivity.java (em inglês)

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. Substitua o callback onCreate() e acesse a visualização adicionada pelo 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. Incluímos uma implementação de FistDrawListener, que tem dois callbacks: onDrawingStart() e onDrawingFinish() (consulte a próxima seção abaixo para mais detalhes sobre FirstDrawListener e o que pode afetar o desempenho dela). Registre o FirstDrawListener ao final do callback onCreate() da atividade. Interrompa o viewLoadTrace no callback onDrawingFinish().

TestActivity.java (em inglês)

    // 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. Execute o app novamente. Depois, filtre o Logcat com "Métrica de trace do Logging". Toque no botão LOAD ACTIVITY e procure registros como abaixo:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Parabéns! Você mediu o tempo de carregamento de uma atividade e informou os dados ao Monitoramento de desempenho do Firebase. Veremos a métrica gravada no Console do Firebase mais adiante neste codelab.

Finalidade do FirstDrawListener

Na seção acima, registramos um FirstDrawListener. O objetivo do FirstDrawListener é medir quando o primeiro frame começou e terminou de ser desenhado.

Ela implementa ViewTreeObserver.OnDrawListener e substitui o callback onDraw() que é invocado quando a árvore de visualização está prestes a ser desenhada. Em seguida, ele encapsula o resultado para fornecer dois callbacks de utilitários, onDrawingStart() e onDrawingFinish().

O código completo de FirstDrawListener pode ser encontrado no código-fonte deste codelab.

6. Medir o tempo de carregamento de um fragmento

A medição do tempo de carregamento de um fragmento é semelhante à medição de uma atividade, mas com algumas pequenas diferenças. Novamente, instrumentaremos um trace de código personalizado:

  1. Substitua o callback onAttach() e comece a gravar fragmentLoadTrace. Vamos nomear esse trace como Test-Fragment-LoadTime.

Conforme explicado em uma etapa anterior, o objeto Fragment pode ser criado a qualquer momento, mas fica ativo somente quando é anexado à atividade host.

TestFragment.java (em inglês)

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 o FirstDrawListener no callback onViewCreated(). Em seguida, de forma semelhante ao exemplo da atividade, pare o rastro no onDrawingFinish().

TestFragment.java (em inglês)

@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. Execute o app novamente. Depois, filtre o Logcat com "Métrica de trace do Logging". Toque no botão LOAD FRAGMENT e procure registros como abaixo:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Parabéns! Você mediu o tempo de carregamento de um fragmento e informou os dados ao Monitoramento de desempenho do Firebase. Veremos a métrica gravada no Console do Firebase mais adiante neste codelab.

7. Compreensão da renderização de tela e o que é um frame lento/congelado

Renderização da interface é o ato de gerar um frame do seu app e exibi-lo na tela. Para garantir que a interação do usuário com o app seja suave, ele precisa renderizar frames em menos de 16 ms para atingir 60 quadros por segundo ( por que 60 fps?). Se o app tiver uma renderização lenta da interface, o sistema será forçado a pular frames, e o usuário vai perceber a renderização lenta do app. Chamamos isso de instabilidade.

Da mesma forma, frames congelados são frames de interface que levam mais de 700 ms para serem renderizados. Esse atraso é um problema porque seu app parece estar travado e não responde à entrada do usuário por quase um segundo enquanto o frame está renderizando.

8. Medir os frames lentos/congelados de um fragmento

O Monitoramento de desempenho do Firebase captura automaticamente frames lentos/congelados para uma atividade, mas somente se ela for acelerada por hardware. No entanto, esse recurso não está disponível para fragmentos no momento. Os frames lentos/congelados de um fragmento são definidos como os frames lentos/congelados para toda a atividade entre os callbacks onFragmentAttached() e onFragmentDetached() no ciclo de vida do fragmento.

Com a motivação da classe AppStateMonitor, que faz parte do SDK do Monitoramento de desempenho responsável por gravar traces de tela para a atividade, implementamos a classe ScreenTrace (que faz parte deste repositório de código-fonte do codelab). A classe ScreenTrace pode ser vinculada ao callback do ciclo de vida de FragmentManager da atividade para capturar frames lentos/congelados. Essa classe fornece duas APIs públicas:

  • recordScreenTrace(): começa a gravar um trace de tela
  • sendScreenTrace(): interrompe a gravação de um trace de tela e anexa métricas personalizadas para registrar contagens de frames totais, lentos e congelados.

Ao anexar essas métricas personalizadas, os traces de tela para fragmentos podem ser processados da mesma forma que os traces de tela de uma atividade e podem ser exibidos com outros traces de renderização de tela no painel Desempenho do Console do Firebase.

Veja como registrar traces de tela para seu fragmento:

  1. Inicialize a classe ScreenTrace na atividade que hospeda o fragmento.

MainActivity.java (em inglês)

// 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. Ao carregar seu fragmento, registre-se em FragmentLifecycleCallbacks e substitua os callbacks onFragmentAttached() e onFragmentDetached(). Fizemos isso para você. É necessário começar a gravar traces de tela no callback onFragmentAttached() e interromper a gravação no callback onFragmentDetached().

MainActivity.java (em inglês)

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. Execute o app novamente. Em seguida, toque no botão LOAD FRAGMENT. Aguarde alguns segundos e clique no back button na barra de navegação inferior.

Filtre o logcat por "Logging trace metric" e depois procure por registros como estes:

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

Filtre o Logcat com "FireperfViews" e procure registros como estes:

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

🎉 Parabéns! Você mediu os frames lentos/congelados de um fragmento e informou esses dados ao Monitoramento de desempenho do Firebase. Veremos as métricas gravadas no Console do Firebase mais adiante neste codelab.

9. Verificar métricas no Console do Firebase

  1. No logcat, clique no URL do Console do Firebase para acessar a página de detalhes de um trace. ceb9d5ba51bb6e89.jpeg

Como alternativa, no Console do Firebase, selecione o projeto que contém seu aplicativo. No painel esquerdo, localize a seção Versões e Monitorar e em Desempenho.

  • Na guia principal Painel, role para baixo até a tabela de traces e clique na guia Traces personalizados. Nesta tabela, você vai encontrar os traces de código personalizados que adicionamos anteriormente, além de alguns traces prontos para uso, como _app_start.
  • Encontre os dois traces de código personalizados, TestActivity-LoadTime e TestFragment-LoadTime. Clique na Duração de um dos dois para ver mais detalhes sobre os dados coletados.

a0d8455c5269a590.png

  1. A página de detalhes do trace de código personalizado mostra informações sobre a duração do trace (ou seja, o tempo de carregamento medido).

5e92a307b7410d8b.png

  1. Também é possível visualizar os dados de desempenho do seu trace de tela personalizado.
  • Volte para a guia principal do Painel, role para baixo até a tabela de traces e clique na guia Renderização de tela. Nesta tabela, você vai encontrar os traces de tela personalizados que adicionamos anteriormente, além dos traces de tela prontos para uso, como MainActivity.
  • Encontre seu trace de tela personalizado, MainActivity-TestFragment. Clique no nome do trace para ver os dados agregados de renderização lenta e frames congelados.

ee7890c7e2c28740.png

10. Parabéns

Parabéns! Você mediu o tempo de carregamento e o desempenho da renderização de tela de uma atividade e de um fragmento com o Monitoramento de desempenho do Firebase.

O que você realizou

A seguir

O Firebase Performance oferece mais formas de medir o desempenho do seu app além do rastreamento personalizado. Ele mede automaticamente o tempo de inicialização do app e os dados de desempenho do app em primeiro e em segundo plano. É hora de verificar essas métricas no Console do Firebase.

Além disso, o Firebase Performance oferece monitoramento automático de solicitações de rede HTTP/S. Com isso, você pode instrumentar facilmente as solicitações de rede sem escrever uma única linha de código. Tente enviar algumas solicitações de rede do seu app e encontre as métricas no Console do Firebase.

Bônus

Agora que você sabe como medir o tempo de carregamento e o desempenho de renderização de tela da sua atividade/fragmento usando traces de código personalizados, confira nossa base de código aberto para saber se consegue capturar essas métricas prontas para uso em qualquer atividade/fragmento que faça parte do app. Se quiser, pode mandar o RP :-)

11. Aprendizagem extra

Entender o que acontece durante o carregamento de uma atividade ajuda a entender melhor as características de desempenho do app. Em uma etapa anterior, descrevemos em detalhes o que acontece durante o carregamento de uma atividade, mas o diagrama a seguir descreve cada fase com muito mais detalhes.

cd61c1495fad7961.png