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

1. Introdução

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

Por que precisamos medir o desempenho das Views?

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 UI que contém os componentes de visualização com os quais os usuários interagem. Os usuários não conseguem ver todo o conteúdo da IU até que ele esteja completamente desenhado na tela. Telas lentas e congeladas prejudicarão diretamente a interação do usuário com seu aplicativo e criarão 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 Firebase Performance Monitoring 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 da primeira atividade) e o desempenho de renderização da tela (ou seja, frames 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 visualizaçõ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 atividades e fragmentos instrumentando rastreamentos de código personalizados em seu aplicativo. Você pode estender facilmente este codelab para medir o desempenho dos componentes da visualização personalizada.

O que você aprenderá

  • Como adicionar o Firebase Performance Monitoring a um aplicativo Android
  • Compreendendo o carregamento de uma atividade ou fragmento
  • Como instrumentar rastreamentos de código personalizados para medir o tempo de carregamento de uma atividade ou fragmento
  • Noções básicas sobre renderização de tela e o que é um quadro lento/congelado
  • Como instrumentar rastreamentos de código personalizados com métricas para registrar 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 a falta de um arquivo google-services.json . Corrigiremos isso na próxima seção desta etapa.

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

Conecte seu aplicativo ao Firebase

  1. Acesse Android Studio / Ajuda > Verificar atualizações para ter certeza de que está 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 Começar com 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 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

Adicione o monitoramento de desempenho ao seu aplicativo

No painel Assistente do Android Studio, clique em Adicionar monitoramento de desempenho ao seu aplicativo .

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

9b58145acc4be030.png

Por fim, você deverá ver a mensagem de sucesso no painel Assistente do 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 o 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 êxito ao SDK do Monitoramento de desempenho, o projeto deverá ser compilado agora. No Android Studio, clique em Executar > Executar 'app' para criar e executar o aplicativo em seu dispositivo/emulador Android conectado.

O aplicativo possui dois botões que levam você a uma Atividade e Fragmento correspondente, 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 da sua atividade ou fragmento.

4. Compreender o carregamento de uma atividade ou fragmento

Nesta etapa aprenderemos o que o sistema está fazendo durante o carregamento de uma Atividade ou Fragmento.

Compreendendo o carregamento de uma atividade

Para uma Activity, o tempo de carregamento é definido como o tempo a partir do momento em que o objeto Activity é criado até o primeiro quadro ser completamente desenhado na tela ( é quando o usuário verá a UI completa da Activity pela primeira vez). 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 visualizar hierarquias.

Em um nível superior, quando seu aplicativo 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 o momento em que o usuário vê a IU da 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 da Visualização do Fragmento seja completamente desenhado na tela.

5. Meça o tempo de carregamento de uma atividade

Atrasos no primeiro quadro podem levar a uma experiência ruim para o usuário, 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 personalizado (denominado 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 retorno de chamada 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 possui dois retornos de chamada: onDrawingStart() e onDrawingFinish() (veja 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 retorno de chamada onCreate() da Activity. Você deve interromper 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 os registros como abaixo:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)

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

Objetivo do FirstDrawListener

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

Ele implementa ViewTreeObserver.OnDrawListener e substitui o retorno de chamada 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 Fragment é semelhante a como medimos para uma Activity, mas com algumas pequenas diferenças. Novamente, instrumentaremos 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 ele se torna ativo somente quando é anexado à sua atividade hospedeira.

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 de Activity, interrompa o rastreamento em 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 os registros como abaixo:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)

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

7. Noções básicas sobre renderização de tela e o que é um quadro lento/congelado

UI Rendering é o ato de gerar um frame do seu aplicativo e exibi-lo na tela. Para garantir que a interação do usuário com seu aplicativo seja tranquila, seu aplicativo deve renderizar quadros em menos de 16ms para atingir 60 quadros por segundo ( por que 60fps? ). Se o seu aplicativo apresentar renderização lenta da interface do usuário, o sistema será forçado a pular quadros e o usuário perceberá falhas no seu aplicativo. Chamamos isso de brincadeira .

Da mesma forma, frames congelados são frames de UI que levam mais de 700 ms para serem renderizados. 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 Firebase Performance Monitoring captura automaticamente quadros lentos/congelados para uma atividade ( mas apenas se for acelerada por hardware ). No entanto, esse recurso não está disponível atualmente para Fragmentos. 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.

Inspirados na classe AppStateMonitor ( que faz parte do SDK do Performance Monitoring 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 Activity 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 contagens de quadros totais, lentos e congelados

Ao anexar essas métricas personalizadas, os rastreamentos de tela para fragmentos podem ser tratados da mesma forma que os rastreamentos de tela de 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 Fragment:

  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 em FragmentLifecycleCallbacks e substitua os retornos de chamada 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 a gravação 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 quadros lentos/congelados de um fragmento e relatou esses dados ao Firebase Performance Monitoring. Veremos as métricas registradas no Firebase Console posteriormente neste codelab.

9. Verifique as métricas no console do Firebase

  1. No logcat, clique no URL do console do Firebase 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 aplicativo. No painel esquerdo, localize a seção Liberar e monitorar e clique em Desempenho .

  • Na guia Painel principal, role para baixo até a tabela de rastreamentos e clique na guia Rastreamentos personalizados . Nesta tabela, você verá os rastreamentos de código personalizados que adicionamos anteriormente, além de alguns rastreamentos prontos para uso , como o rastreamento _app_start .
  • Encontre seus dois rastreamentos de código personalizados, TestActivity-LoadTime e TestFragment-LoadTime . Clique na Duração de qualquer um 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 do 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 rastreamento 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 Firebase Performance Monitoring!

O que você realizou

Qual é o próximo

O desempenho do Firebase oferece mais formas de medir o 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 . Chegou a hora de você verificar essas métricas no Firebase Console .

Além disso, o Firebase Performance oferece monitoramento automático de solicitações de rede HTTP/S . Com isso você pode instrumentar facilmente 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 de código aberto para ver se consegue capturar essas métricas imediatamente 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