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, a atividade ou o 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 para o usuário.
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 uma 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, geralmente é útil entender como medir o tempo de carregamento e o desempenho da renderização de tela de atividades e fragmentos instrumentando traces de código personalizados no app. Este codelab pode ser facilmente estendido 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 um fragmento
- Como instrumentar traces de código personalizados para medir o tempo de carregamento de uma atividade ou um 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 abaixo 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. Você provavelmente vai encontrar alguns erros de compilação ou 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 > Verifique se há atualizações para confirmar se você está 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 e um novo app do Firebase.
- Em seguida, você verá uma caixa de diálogo para Conectar o novo app 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 etapas a seguir deste codelab, você vai aprender a medir o tempo de carregamento e o desempenho da renderização de 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é o primeiro quadro ser completamente desenhado na tela. quando o usuário verá a interface completa da atividade pela primeira vez. Para saber se o app está totalmente renderizado, use o método reportFullyDrawn()
e confira o tempo decorrido entre a inicialização do app e a exibição completa de todos os recursos e das hierarquias de visualização.
Em um nível alto, 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 da atividade na tela.
Noções básicas sobre o carregamento de um fragmento
Semelhante à atividade, o tempo de carregamento de um fragmento é definido como o momento em que o fragmento é anexado à atividade host até que o primeiro frame da visualização de fragmento seja completamente desenhado 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 Activity assim que o objeto Activity 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). Registre oFirstDrawListener
ao final do callbackonCreate()
da atividade. Pare oviewLoadTrace
no callbackonDrawingFinish()
.
TestActivity.java (em inglês)
// 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. Depois, filtre o Logcat com "Métrica de trace do Logging". 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 os dados ao Monitoramento de desempenho do Firebase. Vamos conferir a métrica registrada no console do Firebase mais adiante neste codelab.
Finalidade do 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
A medição do tempo de carregamento de um fragmento é semelhante à medição de uma atividade, mas com algumas pequenas diferenças. Novamente, vamos instrumentar um trace de código personalizado:
- Substitua o callback
onAttach()
e comece a gravarfragmentLoadTrace
. Vamos nomear o trace 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 (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 registro de rastro. Toque no botão
LOAD FRAGMENT
e procure registros como abaixo:
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. Veremos a métrica gravada 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 pular 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 de interface que levam mais de 700 ms para serem renderizados. 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 para 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 oferece 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 traces de tela para seu fragmento:
- Inicialize a classe
ScreenTrace
na atividade que hospeda o fragmento.
MainActivity.java (em inglês)
// 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ê. É necessário começar a gravar traces de tela no callbackonFragmentAttached()
e interromper 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 noback button
na barra de navegação inferior.
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 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 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 rastros 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 na Duração de um dos dois para ver 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 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ções
- 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, de apps 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 da tela da sua atividade/fragmento usando rastros 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? Se quiser, pode mandar o RP :-)
11. Aprendizagem bônus
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.