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, sua atividade ou 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 IU 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.
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 (por exemplo, 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 sim uma atividade 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, é útil entender como medir o tempo de carregamento e o desempenho de renderização da tela de atividades e fragmentos instrumentando traces de código personalizados no app. É possível estender facilmente 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 app Android
- Noções básicas sobre o carregamento de uma atividade ou de um fragmento
- Como instrumentar traces de código personalizados para medir o tempo de carregamento de uma atividade ou um fragmento.
- Noções básicas sobre 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 conferir 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 vai 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
Se você não tiver o git na sua máquina, também poderá fazer o download do código diretamente do GitHub.
Importe o projeto measure-view-performance-start
para o Android Studio. Provavelmente você vai encontrar alguns erros de compilação ou talvez 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
- 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.
- Selecione Ferramentas > Firebase para abrir o painel do Assistente.
- Escolha Monitoramento de desempenho para adicionar ao app e clique em Começar a usar o Monitoramento de desempenho.
- Clique em Conectar ao Firebase para conectar seu projeto do Android ao Firebase (isso abrirá o console do Firebase no seu navegador).
- 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 do Firebase e um novo app do Firebase.
- Em seguida, uma caixa de diálogo vai aparecer para conectar o novo app do Firebase ao projeto do Android Studio.
- No painel Assistente do Android Studio, você verá a confirmação de que o app está conectado ao Firebase.
Adicionar o Monitoramento de desempenho ao app
No painel Assistente do Android Studio, clique em Adicionar o Monitoramento de desempenho ao 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.
Por fim, você vai ver a mensagem de sucesso no painel Assistente no Android Studio, indicando que todas as dependências foram configuradas corretamente.
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 > Run "app" para criar e executar o app no dispositivo/emulador Android conectado.
O app tem dois botões que levam você a uma atividade e um fragmento correspondentes, como este:
Nas próximas etapas deste codelab, você vai aprender a medir o tempo de carregamento e o desempenho de renderização da 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é que o primeiro frame seja totalmente renderizado na tela (é quando o usuário vai ver a interface completa da atividade pela primeira vez). Para medir se o app está totalmente renderizado, use 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 das hierarquias de visualização.
De modo geral, quando o app chama startActivity(Intent)
, o sistema executa automaticamente os processos a seguir. 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.
Como entender o carregamento de um fragmento
Assim como na atividade, o tempo de carregamento de um fragmento é definido como o tempo que começa quando o fragmento é anexado à atividade host até que o primeiro frame da visualização do fragmento seja totalmente renderizado 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:
- Inicie o rastreamento de código personalizado (chamado
TestActivity-LoadTime
) na classe de atividade assim que o objeto de atividade 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");
// ...
}
- Substitua o callback
onCreate()
e adicione a visualização pelo 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);
// ...
}
- Incluímos uma implementação de
FistDrawListener
, que tem dois callbacks:onDrawingStart()
eonDrawingFinish()
(consulte a próxima seção abaixo para mais detalhes sobreFirstDrawListener
e o que pode afetar o desempenho dela). Registre oFirstDrawListener
no final do callbackonCreate()
da atividade. Interrompa oviewLoadTrace
no callbackonDrawingFinish()
.
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();
}
});
- Execute o app novamente. Em seguida, filtre o logcat com Métrica de rastreamento de registro. 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 da FirstDrawListener
é medir quando o primeiro frame começou e terminou de ser desenhado.
Ele implementa o ViewTreeObserver.OnDrawListener
e substitui o callback onDraw()
, que é invocado quando a árvore de visualização está prestes a ser renderizada. Em seguida, ele envolve o resultado para fornecer dois callbacks de utilitário 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:
- Substitua o callback
onAttach()
e comece a gravar ofragmentLoadTrace
. Vamos nomear esse trace comoTest-Fragment-LoadTime
.
Conforme explicado em uma etapa anterior, o objeto Fragment pode ser criado a qualquer momento, mas fica ativo somente quando está anexado à atividade 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");
}
- Registre o
FirstDrawListener
no callbackonViewCreated()
. Em seguida, de forma semelhante ao exemplo da atividade, pare o rastro noonDrawingFinish()
.
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();
}
});
- Execute o app novamente. Em seguida, filtre o logcat com Métrica de rastreamento de registro. Toque no botão
LOAD FRAGMENT
e procure registros como este:
I/FirebasePerformance: Logging trace metric: TestFragment-LoadTime (duration: XXXms)
🎉 Parabéns! Você mediu o tempo de carregamento de um fragmento e informou esses dados ao Monitoramento de desempenho do Firebase. Vamos conferir a métrica registrada no console do Firebase mais adiante neste codelab.
7. Noções básicas sobre renderização de tela e o que é um frame lento/congelado
A renderização da interface é o ato de gerar um frame do seu app e mostrá-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 ignorar frames, e o usuário vai perceber a renderização lenta do app. Chamamos isso de instabilidade.
Da mesma forma, os frames congelados são frames da interface que levam mais de 700 ms para renderização. Esse atraso é um problema porque o 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 de 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 de 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 conectada ao callback do ciclo de vida FragmentManager
da atividade para capturar frames lentos/congelados. Essa classe fornece duas APIs públicas:
recordScreenTrace()
: começa a gravar um trace de telasendScreenTrace()
: 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 rastros de tela para fragmentos podem ser processados da mesma forma que os rastros de tela para uma atividade e podem ser exibidos com outros rastros de renderização de tela no painel Performance do console do Firebase.
Veja como registrar rastros de tela para seu fragmento:
- Inicialize a classe
ScreenTrace
na atividade que hospeda o 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);
// ...
}
- Ao carregar seu fragmento, registre-se em
FragmentLifecycleCallbacks
e substitua os callbacksonFragmentAttached()
eonFragmentDetached()
. Fizemos isso para você. Você precisa iniciar a gravação de rastros de tela no callbackonFragmentAttached()
e parar a gravação no callbackonFragmentDetached()
.
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);
}
};
- Execute o app novamente. Em seguida, toque no botão
LOAD FRAGMENT
. Aguarde alguns segundos e clique emback button
na barra de navegação na parte de baixo.
Filtre o logcat com Métrica de registro de trace e procure registros como este:
I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)
Filtre o Logcat com FireperfViews e procure registros como este:
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
- No logcat, clique no URL do Console do Firebase para acessar a página de detalhes de um trace.
Como alternativa, no Console do Firebase, selecione o projeto que tem seu app. No painel à esquerda, localize a seção Liberação e monitoramento e clique em Performance.
- Na guia principal Painel, role a tela para baixo até a tabela de traces e clique na guia Traces personalizados. Nesta tabela, você vai encontrar os rastros de código personalizados que adicionamos anteriormente, além de alguns traces prontos para uso, como o trace
_app_start
. - Encontre os dois traces de código personalizados,
TestActivity-LoadTime
eTestFragment-LoadTime
. Clique em Duração em qualquer uma delas para conferir mais detalhes sobre os dados coletados.
- 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).
- Você também pode conferir os dados de desempenho do seu rastreamento de tela personalizado.
- Volte para a guia principal Painel, role para baixo até a tabela de rastros e clique na guia Renderização de tela. Nesta tabela, você vai encontrar os rastros de tela personalizados que adicionamos anteriormente, além de rastros de tela prontos para uso, como o rastro
MainActivity
. - Encontre o rastro de tela personalizado,
MainActivity-TestFragment
. Clique no nome do trace para ver os dados agregados de renderização lenta e frames congelados.
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
- Você integrou o Monitoramento de desempenho do Firebase a um app de exemplo
- Agora você entende o ciclo de vida do carregamento de visualização
- Você mediu o tempo de carregamento de uma atividade e um fragmento adicionando traces de código personalizados.
- Você gravou frames lentos/congelados adicionando traces de tela personalizados com métricas personalizadas.
A seguir
O Firebase Performance oferece mais maneiras 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, é possível instrumentar facilmente as solicitações de rede sem precisar escrever uma única linha de código. Você pode tentar enviar algumas solicitações de rede do seu app 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 da sua atividade/fragmento usando traces de código personalizados, confira nossa base de código aberto para saber se é possível 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.