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 essencial 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 interface até que ele seja totalmente renderizado 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 fornece essas métricas de desempenho de forma nativa?
O Monitoramento de desempenho do Firebase captura automaticamente alguns dados de desempenho prontos para uso, como o horário de início do app (ou seja, o tempo de carregamento da primeira atividade) e a performance de renderização da 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 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
- Entender o carregamento de uma atividade ou um fragmento
- Como instrumentar rastros de código personalizados para medir o tempo de carregamento de uma atividade ou fragmento
- Entender a 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 a seguir para clonar o código de exemplo deste 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 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 projeto do Android. Tudo isso no Android Studio.
Conectar seu app ao Firebase
- Acesse Android Studio/Help > Check for updates para garantir que você esteja usando as versões mais recentes do Android Studio e do Firebase Assistente.
- Selecione Tools > Firebase para abrir o painel 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 Android ao Firebase (isso vai abrir o console do Firebase no seu navegador).
- No console do Firebase, clique em Adicionar projeto e insira um nome de projeto do Firebase (se você já tiver um projeto do Firebase, selecione esse projeto). 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 Android Studio, no painel Assistant, você vai encontrar 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 Aceitar mudanças vai aparecer. Depois disso, o Android Studio vai sincronizar seu app para garantir que todas as dependências necessárias foram 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 o app ao SDK do Monitoramento de desempenho, o projeto vai 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 fragmento.
Como entender 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 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 interface dela 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
Atrasos no primeiro frame podem levar a uma experiência ruim do usuário. Por isso, é importante entender o atraso de carregamento inicial que seus usuários estão enfrentando. É 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
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 saber mais sobreFirstDrawListener
e o que pode afetar o desempenho. Registre oFirstDrawListener
no final do callbackonCreate()
da atividade. Pare 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 este:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)
🎉 Parabéns! Você mediu o tempo de carregamento de uma atividade e informou esses dados ao Monitoramento de desempenho do Firebase. Vamos conferir a métrica registrada no console do Firebase mais adiante neste codelab.
Finalidade de FirstDrawListener
Na seção acima, registramos um FirstDrawListener
. O propósito de FirstDrawListener
é medir quando o primeiro frame começou e terminou de ser renderizado.
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
Medir o tempo de carregamento de um fragmento é semelhante a como medimos para uma atividade, mas com algumas pequenas diferenças. Novamente, vamos instrumentar um trace de código personalizado:
- Substitua o callback
onAttach()
e comece a gravar ofragmentLoadTrace
. Vamos nomear esse rastro comoTest-Fragment-LoadTime
.
Como explicado em uma etapa anterior, o objeto Fragment pode ser criado a qualquer momento, mas só fica ativo quando é anexado à atividade 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");
}
- Registre o
FirstDrawListener
no callbackonViewCreated()
. Em seguida, semelhante ao exemplo de atividade, interrompa o rastreamento noonDrawingFinish()
.
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();
}
});
- 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. Entender a 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. 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.
Usando a classe AppStateMonitor
(que faz parte do SDK do Monitoramento de desempenho responsável por gravar rastros de tela para a atividade), implementamos a classe ScreenTrace
(que faz parte do repositório de código fonte deste codelab). A classe ScreenTrace
pode ser conectada ao callback do ciclo de vida FragmentManager
da atividade para capturar frames lentos/congelados. Essa classe oferece duas APIs públicas:
recordScreenTrace()
: inicia a gravação de um trace de telasendScreenTrace()
: interrompe a gravação de um trace de tela e anexa métricas personalizadas para registrar as contagens de frames total, lento e congelado
Ao anexar essas métricas personalizadas, os rastros de tela de fragmentos podem ser processados da mesma forma que os rastros de tela de 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 o fragmento, registre-o para
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
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 e 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. Vamos conferir as métricas registradas no console do Firebase mais adiante neste codelab.
9. Verificar as métricas no console do Firebase
- No logcat, clique no URL do console do Firebase para acessar a página de detalhes de um rastro.
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 rastros 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).
- Também é possível conferir os dados de performance 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 da tela personalizado,
MainActivity-TestFragment
. Clique no nome do trace para conferir os dados agregados de renderização lenta e frames congelados.
10. Parabéns
Parabéns! Você mediu o tempo de carregamento e o desempenho de renderização da tela de uma atividade e um fragmento usando 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 dados de desempenho de inicialização, em primeiro plano 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, pode conferir nossa base de código de código aberto para saber se é possível capturar essas métricas de forma imediata para qualquer atividade/fragmento que faça parte do app? Fique à vontade para enviar o comunicado de imprensa, se quiser :-)
11. Aprendizagem extra
Entender o que acontece durante o carregamento de uma atividade vai ajudar você a entender melhor as características de desempenho do app. Em uma etapa anterior, descrevemos de forma geral o que acontece durante o carregamento de uma atividade, mas o diagrama a seguir descreve cada fase com muito mais detalhes.