Meça o tempo de carregamento e a renderização da tela com o Firebase Performance Monitoring

1. Introdução

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

Por que precisamos medir o desempenho das visualizações?

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

O Monitoramento de desempenho do Firebase não fornece 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 aplicativo (ou seja, o tempo de carregamento apenas para sua primeira atividade) e o desempenho de renderização da tela (ou seja, quadros lentos e congelados para atividades, mas não para Fragmentos). No entanto, os aplicativos da indústria geralmente não têm muitas atividades, mas sim uma atividade e vários fragmentos. Além disso, muitos aplicativos geralmente implementam suas próprias exibições personalizadas para casos de uso mais complexos. Portanto, muitas vezes é útil entender como medir o tempo de carregamento e o desempenho de renderização de tela de Activities e Fragments instrumentando rastreamentos de código personalizados em seu aplicativo. Você pode facilmente estender este codelab para medir o desempenho dos componentes de visualização personalizada.

O que você aprenderá

  • Como adicionar o monitoramento de desempenho do Firebase a um aplicativo Android
  • Entendendo o carregamento de uma atividade ou um fragmento
  • Como instrumentar rastreamentos de código personalizados para medir o tempo de carregamento de uma atividade ou fragmento
  • Compreendendo a renderização de tela e o que é um quadro lento/congelado
  • Como instrumentar rastreamentos de código personalizados com métricas para gravar telas lentas/congeladas
  • Como visualizar as métricas coletadas no console do Firebase

O que você precisará

  • Android Studio 4.0 ou superior
  • Um dispositivo/emulador Android
  • Java versão 8 ou superior

2. Preparando-se

Obtenha o código

Execute os comandos a seguir para clonar o código de amostra deste codelab. Isso criará uma pasta chamada codelab-measure-android-view-performance em sua máquina:

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

Caso não tenha o git em sua máquina, você também pode baixar o código diretamente do GitHub.

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

Neste codelab, usaremos o plug-in Firebase Assistant para registrar nosso aplicativo Android com um projeto Firebase e adicionar os arquivos de configuração, plug-ins e dependências necessários do Firebase ao nosso projeto Android, tudo de dentro do Android Studio !

Conecte seu aplicativo ao Firebase

  1. Acesse Android Studio / Help > Check for updates para garantir que você esteja usando as versões mais recentes do Android Studio e do Firebase Assistant.
  2. Selecione Ferramentas > Firebase para abrir o painel Assistente .

e791bed0999db1e0.png

  1. Escolha Monitoramento de desempenho para adicionar ao seu aplicativo e clique em Introdução ao Monitoramento de desempenho .
  2. Clique em Conectar ao Firebase para conectar seu projeto Android ao Firebase (isso abrirá o console do Firebase em seu navegador) .
  3. No console do Firebase, clique em Adicionar projeto e insira um nome de projeto do Firebase (se você já tiver um projeto do Firebase, poderá selecionar esse projeto existente) . Clique em Continuar e aceite os termos para criar o projeto Firebase e um novo aplicativo Firebase.
  4. Em seguida, você verá uma caixa de diálogo para conectar seu novo aplicativo Firebase ao seu projeto do Android Studio.

42c498d28ead2b77.png

  1. De volta ao Android Studio, no painel Assistente , você verá a confirmação de que seu aplicativo está conectado ao Firebase.

dda8bdd9488167a0.png

Adicionar monitoramento de desempenho ao seu aplicativo

No painel Assistant do Android Studio, clique em Add Performance Monitoring to your app .

Você deve ver uma caixa de diálogo para aceitar alterações, após a qual o Android Studio deve sincronizar seu aplicativo para garantir que todas as dependências necessárias foram adicionadas.

9b58145acc4be030.png

Por fim, você deve ver a mensagem de sucesso no painel Assistant no Android Studio informando que todas as dependências estão configuradas corretamente.

aa0d46fc944e0c0b.png

Como etapa adicional, habilite o log de depuração seguindo as instruções na etapa "(Opcional) Habilitar log 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 aplicativo com sucesso ao SDK de monitoramento de desempenho, o projeto agora deve compilar. No Android Studio, clique em Executar > Executar 'aplicativo' para compilar e executar o aplicativo em seu dispositivo/emulador Android conectado.

O aplicativo possui dois botões que levam você a uma atividade e um fragmento correspondentes, como este:

410d8686b4f45c33.png

Nas etapas a seguir deste codelab, você aprenderá a medir o tempo de carregamento e o desempenho de renderização de tela de sua Activity ou Fragment.

4. Entendendo o carregamento de uma Activity ou Fragment

Nesta etapa, aprenderemos o que o sistema está fazendo durante o carregamento de uma Activity ou Fragment.

Entendendo o carregamento de uma atividade

Para uma Activity, o tempo de carregamento é definido como o tempo desde quando o objeto Activity é criado até o primeiro quadro ser completamente desenhado na tela ( é quando o usuário verá a IU completa para a Activity para o primeiro tempo ). Para medir se seu aplicativo está totalmente desenhado, você pode usar o método reportFullyDrawn() para medir o tempo decorrido entre a inicialização do aplicativo e a exibição completa de todos os recursos e hierarquias de exibição.

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

c20d14b151549937.png

Compreendendo o carregamento de um fragmento

Semelhante à atividade, o tempo de carregamento de um fragmento é definido como o tempo a partir do momento em que o fragmento é anexado à sua atividade host até que o primeiro quadro para a exibição do fragmento seja completamente desenhado na tela.

5. Medir o tempo de carregamento de uma Activity

Atrasos no primeiro quadro podem levar a uma experiência de usuário ruim, por isso é importante entender quanto atraso de carregamento inicial seus usuários estão enfrentando. Você pode instrumentar um rastreamento de código personalizado para medir esse tempo de carregamento:

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

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. Substitua o callback onCreate() e obtenha a View 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 retornos de chamada: onDrawingStart() e onDrawingFinish() (consulte a próxima seção abaixo para obter mais detalhes sobre FirstDrawListener e o que pode afetar seu desempenho) . Registre o FirstDrawListener no final do callback onCreate() da Activity. Você deve parar seu viewLoadTrace no retorno de chamada 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. Execute novamente o aplicativo. Em seguida, filtre o logcat com " Logging trace metric ". Toque no botão LOAD ACTIVITY e procure por logs como abaixo:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

🎉 Parabéns! Você mediu com sucesso o tempo de carregamento de uma Activity e relatou esses dados ao Firebase Performance Monitoring. Veremos a métrica registrada no console do Firebase posteriormente neste codelab.

Finalidade do FirstDrawListener

Na seção logo acima, registramos um FirstDrawListener . O objetivo de FirstDrawListener é medir quando o primeiro quadro começou e terminou o desenho.

Ele implementa o ViewTreeObserver.OnDrawListener e substitui o callback onDraw() que é invocado quando a árvore View está prestes a ser desenhada. Em seguida, ele agrupa o resultado para fornecer dois retornos de chamada de utilitário onDrawingStart() e onDrawingFinish() .

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

6. Meça o tempo de carregamento de um fragmento

Medir o tempo de carregamento de um fragmento é semelhante a como o medimos para uma atividade, mas com algumas pequenas diferenças. Novamente, vamos instrumentar um rastreamento de código personalizado :

  1. Substitua o retorno de chamada onAttach() e comece a gravar seu fragmentLoadTrace . Chamaremos esse rastreamento Test-Fragment-LoadTime .

Conforme explicado em uma etapa anterior, o objeto Fragment pode ser criado a qualquer momento, mas torna-se ativo apenas quando é anexado à Activity do 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 o FirstDrawListener no retorno de chamada onViewCreated() . Em seguida, semelhante ao exemplo Activity, pare o rastreamento no 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. Execute novamente o aplicativo. Em seguida, filtre o logcat com " Logging trace metric ". Toque no botão LOAD FRAGMENT e procure por logs como abaixo:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

🎉 Parabéns! Você mediu com sucesso o tempo de carregamento de um fragmento e relatou esses dados ao Monitoramento de desempenho do Firebase. Veremos a métrica registrada no console do Firebase posteriormente neste codelab.

7. Compreendendo a renderização de tela e o que é um quadro lento/congelado

A renderização da interface do usuário é o ato de gerar um quadro de seu aplicativo e exibi-lo na tela. Para garantir que a interação do usuário com seu aplicativo seja suave, seu aplicativo deve renderizar quadros em menos de 16 ms para atingir 60 quadros por segundo ( por que 60 fps? ). Se seu aplicativo sofre de renderização de IU lenta, o sistema é forçado a pular quadros e o usuário perceberá gagueira em seu aplicativo. Chamamos isso de jacaré .

Da mesma forma, os quadros congelados são quadros de interface do usuário que levam mais de 700ms para renderizar. Esse atraso é um problema porque seu aplicativo parece estar travado e não responde à entrada do usuário por quase um segundo inteiro enquanto o quadro está sendo renderizado.

8. Meça os quadros lentos/congelados de um fragmento

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

Aproveitando a motivação da classe AppStateMonitor ( que faz parte do SDK de monitoramento de desempenho responsável por registrar rastreamentos de tela para Activity ), implementamos a classe ScreenTrace ( que faz parte deste repositório de código-fonte do codelab ). A classe ScreenTrace pode ser conectada ao retorno de chamada do ciclo de vida do FragmentManager da atividade para capturar quadros lentos/congelados. Esta classe fornece duas APIs públicas:

  • recordScreenTrace() : Inicia a gravação de um rastreamento de tela
  • sendScreenTrace() : Interrompe a gravação de um rastreamento de tela e anexa métricas personalizadas para registrar as contagens de quadro Total, Lento e Congelado

Ao anexar essas métricas personalizadas, os rastreamentos de tela para fragmentos podem ser tratados da mesma forma que os rastreamentos de tela para uma atividade e podem ser exibidos junto com outros rastreamentos de renderização de tela no painel de desempenho do console do Firebase.

Veja como registrar rastreamentos de tela para seu fragmento:

  1. Inicialize a classe ScreenTrace em sua Activity que hospeda o 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. Ao carregar seu Fragment, registre-se para FragmentLifecycleCallbacks e substitua os callbacks onFragmentAttached() e onFragmentDetached() . Nós fizemos isso por você. Você precisa começar a gravar rastreamentos de tela no retorno de chamada onFragmentAttached() e parar de gravar no retorno de chamada 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. Execute novamente o aplicativo. 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 com " Logging trace metric " e procure os logs como abaixo:

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

Filtre o logcat com " FireperfViews " e procure os logs como abaixo:

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

🎉 Parabéns! Você mediu com êxito os frames lentos/congelados de um fragmento e relatou esses dados ao monitoramento de desempenho do Firebase. Veremos as métricas registradas no console do Firebase posteriormente neste codelab.

9. Verifique as métricas no console do Firebase

  1. No logcat, clique no URL do Firebase console para visitar a página de detalhes de um rastreamento. ceb9d5ba51bb6e89.jpeg

Como alternativa, no console do Firebase , selecione o projeto que contém seu app. No painel esquerdo, localize a seção Release & Monitor e clique em Performance .

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

a0d8455c5269a590.png

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

5e92a307b7410d8b.png

  1. Você também pode visualizar os dados de desempenho de seu rastreamento de tela personalizado.
  • Volte para a guia principal do Painel , role para baixo até a tabela de rastreamentos e clique na guia Renderização de tela . Nesta tabela, você verá os rastreamentos de tela personalizados que adicionamos anteriormente, além de quaisquer rastreamentos de tela prontos para uso , como o rastreamento MainActivity .
  • Encontre seu rastreamento de tela personalizado, MainActivity-TestFragment . Clique no nome do traço para visualizar os dados agregados de renderização lenta e quadros congelados.

ee7890c7e2c28740.png

10. Parabéns

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

O que você realizou

Qual é o próximo

O desempenho do Firebase fornece mais formas de medição de desempenho do seu aplicativo além do rastreamento personalizado. Ele mede automaticamente o tempo de inicialização do aplicativo, os dados de desempenho do aplicativo em primeiro plano e do aplicativo em segundo plano . É hora de você 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 facilmente instrumentar solicitações de rede sem escrever uma única linha de código. Você pode tentar enviar algumas solicitações de rede do seu aplicativo e encontrar 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 de sua atividade/fragmento usando rastreamentos de código personalizados, explore nossa base de código aberto para ver se consegue capturar essas métricas prontas para qualquer atividade/fragmento isso faz parte do aplicativo? Sinta-se à vontade para enviar o PR, se desejar :-)

11. Aprendizado Bônus

Entender o que está acontecendo durante o carregamento de uma atividade ajudará você a entender melhor as características de desempenho do seu aplicativo. Em uma etapa anterior, descrevemos em alto nível o que acontece durante o carregamento de uma atividade, mas o diagrama a seguir descreve cada fase com muito mais detalhes.

cd61c1495fad7961.png