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 podem ver todo o conteúdo da interface do usuário até que 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 Firebase Performance Monitoring 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 a hora de início do aplicativo (ou seja, o tempo de carregamento apenas para sua primeira atividade) e o desempenho de renderização de tela (ou seja, frames lentos e congelados para atividades, mas não para Fragmentos). No entanto, os aplicativos do setor 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, geralmente é ú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 facilmente estender este codelab para medir o desempenho dos componentes do Custom View.

O que você vai aprender

  • Como adicionar o Firebase Performance Monitoring 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
  • Entendendo a renderização da 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. Configurando

Obtenha o código

Execute os comandos a seguir para clonar o código de amostra para este 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

Se você não tiver o git em sua máquina, também poderá baixar o código diretamente do GitHub.

Importe o projeto meter 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 do Firebase Assistant para registrar nosso aplicativo Android com um projeto do Firebase e adicionar os arquivos de configuração, plug-ins e dependências do Firebase necessários ao nosso projeto Android — tudo no Android Studio !

Conecte seu aplicativo ao Firebase

  1. Acesse Android Studio / Ajuda > Verificar atualizações 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 do Firebase e um novo aplicativo do Firebase.
  4. Em seguida, você verá uma caixa de diálogo para Conectar seu novo aplicativo do Firebase ao seu projeto do Android Studio.

42c498d28ead2b77.png

  1. De volta ao Android Studio, no painel do 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 no Android Studio, clique em Adicionar monitoramento de desempenho ao seu aplicativo .

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 tenham sido adicionadas.

9b58145acc4be030.png

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

aa0d46fc944e0c0b.png

Como uma 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 sucesso ao SDK do Monitoramento de Desempenho, o projeto agora deve ser compilado. No Android Studio, clique em Executar > Executar 'app' para compilar e executar o aplicativo em seu dispositivo/emulador Android conectado.

O aplicativo possui dois botões que levam você a uma Activity e Fragment correspondente, assim:

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 atividade ou fragmento.

4. Entendendo o carregamento de uma atividade ou fragmento

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

Entendendo o carregamento de uma Activity

Para uma atividade, o tempo de carregamento é definido como o tempo desde quando o objeto Atividade é criado até o primeiro quadro ser completamente desenhado na tela ( é quando o usuário verá a interface do usuário completa para a atividade 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 hierarquias de visualizaçã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 o tempo entre a criação da atividade e quando o usuário vê a interface do usuário da atividade em sua tela.

c20d14b151549937.png

Entendendo o carregamento de um fragmento

Semelhante à atividade, o tempo de carregamento de um fragmento é definido como o tempo a partir de quando o fragmento é anexado à atividade do host até o primeiro quadro da visualização do fragmento ser 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 do 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 (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 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 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 retorno de chamada 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 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 logo acima, registramos um FirstDrawListener . O objetivo do FirstDrawListener é medir quando o primeiro quadro começou e terminou o desenho.

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

O código completo para 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 à forma como o medimos para uma Activity, 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 ele se torna ativo somente quando é anexado à sua Activity 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 de atividade, 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 Firebase Performance Monitoring. Veremos a métrica registrada no console do Firebase posteriormente neste codelab.

7. Entendendo 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 do seu aplicativo e exibi-lo na tela. Para garantir que a interação de um 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 o seu aplicativo sofrer de renderização lenta da interface do usuário, o sistema será forçado a pular quadros e o usuário perceberá gagueira em seu aplicativo. Chamamos isso de jank .

Da mesma forma, frames congelados são frames de interface do usuário que demoram 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 frames lentos/congelados para uma atividade ( mas somente se for acelerado por hardware ). No entanto, esse recurso não está disponível atualmente para Fragments. 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 do Monitoramento de Desempenho responsável por registrar os 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 as contagens de quadros Total, Lento e Congelado

Ao anexar essas métricas personalizadas, os rastreamentos de tela para Fragments 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 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 para FragmentLifecycleCallbacks e substitua os retornos de chamada onFragmentAttached() e onFragmentDetached() . Nós fizemos isso para você. Você precisa iniciar a gravação de 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 por logs como abaixo:

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

Filtre o logcat com " FireperfViews ", então procure por 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 sucesso os frames lentos/congelados de um fragmento e relatou esses dados ao Firebase Performance Monitoring. 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 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 Release & Monitor e clique em Performance .

  • Na guia principal do Painel , 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 _app_start trace.
  • 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 de seu rastreamento de tela personalizado.
  • Volte para a guia principal do Dashboard , role para baixo até a tabela de traces e clique na guia Screen rendering . Nesta tabela, você verá os rastreamentos de tela personalizados que adicionamos anteriormente, além de todos os 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 Firebase Performance 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 . É hora de 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, você pode explorar nossa base de código de código aberto para ver se você pode capturar essas métricas prontas para qualquer atividade/fragmento que é uma parte do aplicativo? Sinta-se à vontade para enviar o PR se desejar :-)

11. Bônus de Aprendizagem

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