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 aplicativos 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 podem ver todo o conteúdo da interface até que ela seja completamente renderizada 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 oferece essas métricas 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 (ou seja, o tempo de carregamento da primeira atividade somente) e o desempenho da renderização de tela (por exemplo, frames lentos e congelados em atividades, mas não em fragmentos). No entanto, os apps do setor geralmente não têm muitas atividades, mas sim uma e vários fragmentos. Além disso, muitos apps geralmente implementam as próprias visualizações personalizadas para casos de uso mais complexos. Portanto, é ú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. Você pode 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 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 registrar telas lentas/congeladas.
- Como visualizar 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 deste codelab. Uma pasta chamada codelab-measure-android-view-performance
será criada 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 máquina, faça o download do código diretamente no GitHub.
Importe o projeto measure-view-performance-start
para o Android Studio. Você provavelmente vai notar 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, usaremos 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 projeto do Android. Tudo isso sem sair do Android Studio.
Conectar seu app ao Firebase
- Acesse Android Studio/Help > Check for updates 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 Introdução ao Monitoramento de desempenho.
- Clique em Conectar ao Firebase para conectar seu projeto do Android ao Firebase. Isso abre o Console do Firebase no seu navegador.
- No Console do Firebase, clique em Adicionar projeto e insira 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 e um novo app do Firebase.
- Em seguida, você verá uma caixa de diálogo para Conectar seu novo app do Firebase ao projeto do Android Studio.
- No painel Assistente do Android Studio, você verá a confirmação de que seu app está conectado ao Firebase.
Adicionar o Monitoramento de desempenho ao app
No painel Assistant no Android Studio, clique em Add Performance Monitoring to your app.
Uma caixa de diálogo Accept Changes vai aparecer. Depois disso, o Android Studio vai sincronizar seu app para garantir que todas as dependências necessárias tenham sido adicionadas.
Por fim, uma mensagem de êxito vai aparecer no painel Assistant do Android Studio informando que todas as dependências estão configuradas corretamente.
Como uma etapa extra, ative a geração de registros de depuração seguindo as instruções em "(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. Executar 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ê 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 faz durante o carregamento de uma atividade ou um fragmento.
Entender o carregamento de uma atividade
Para uma atividade, o tempo de carregamento é definido como o período a partir do momento em que o objeto da atividade foi criado até que o Primeiro frame seja completamente desenhado na tela. Esse é o momento em que o usuário verá a IU completa da atividade pela primeira vez. Para avaliar se o app está totalmente carregado, use o método reportFullyDrawn()
para medir 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 dela na tela.
Noções básicas sobre o carregamento de um fragmento
Semelhante à atividade, o tempo de carregamento de um fragmento é definido como o período entre o momento em que o fragmento é anexado à atividade host e o primeiro frame da visualização do fragmento ser completamente desenhado na tela.
5. Medir o tempo de carregamento de uma atividade
Atrasos no primeiro frame podem prejudicar a experiência do usuário. Por isso, é importante entender o atraso inicial no carregamento dos usuários. É possível instrumentar um trace de código personalizado para medir esse tempo de carregamento:
- Inicie o trace de código personalizado (chamado
TestActivity-LoadTime
) na classe Activity assim que o objeto Activity for criado.
TestActivity.java (link 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");
// ...
}
- Modifique o callback
onCreate()
e acesse a visualização adicionada 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 para saber mais sobreFirstDrawListener
e o que pode afetar a performance dele. Registre oFirstDrawListener
ao final do callbackonCreate()
da atividade. Interrompa oviewLoadTrace
no callbackonDrawingFinish()
.
TestActivity.java (link 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. Em seguida, filtre o logcat com "Logging trace metric". Toque no botão
LOAD ACTIVITY
e procure registros como estes:
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 gravada no Console do Firebase mais adiante neste codelab.
Finalidade do FirstDrawListener
Na seção acima, registramos um FirstDrawListener
. O objetivo do FirstDrawListener
é medir quando o primeiro frame começou e terminou de mostrar.
Ela implementa ViewTreeObserver.OnDrawListener
e substitui o callback onDraw()
, que é invocado quando a árvore de visualização está prestes a ser desenhada. Em seguida, ela une o resultado para fornecer dois callbacks de utilitários onDrawingStart()
e onDrawingFinish()
.
O código completo de FirstDrawListener
pode ser encontrado neste código-fonte do 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 gravar suafragmentLoadTrace
. Vamos nomear este trace comoTest-Fragment-LoadTime
.
Conforme explicado em uma etapa anterior, o objeto do fragmento pode ser criado a qualquer momento, mas só se torna ativo quando está anexado à atividade do host.
TestFragment.java (em inglês)
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 maneira semelhante ao exemplo da atividade, interrompa 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 "Logging trace metric". Toque no botão
LOAD FRAGMENT
e procure registros como estes:
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 gravada 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 pular frames, e o usuário vai notar oscilações no app. Chamamos isso de instabilidade.
Da mesma forma, frames congelados são frames da 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 for com aceleração de 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 registrar os traces de tela da atividade, implementamos a classe ScreenTrace
, que faz parte deste repositório do código-fonte do codelab. A classe ScreenTrace
pode ser vinculada 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 rastro de tela.sendScreenTrace()
: 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 traces de tela para fragmentos podem ser processados da mesma forma que os traces de uma atividade e exibidos com outros traces de renderização de tela no painel Desempenho do Console do Firebase.
Veja como registrar rastreamentos de tela para seu fragmento:
- Inicialize a classe
ScreenTrace
na atividade que hospeda o fragmento.
MainActivity.java (link 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 modifique os callbacksonFragmentAttached()
eonFragmentDetached()
. Fizemos isso para você. É necessário começar a gravar traces de tela no callbackonFragmentAttached()
e parar a gravação no callbackonFragmentDetached()
.
MainActivity.java (link 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 "Logging trace metric" e procure registros como estes:
I/FirebasePerformance: Logging trace metric: _st_MainActivity-TestFragment (duration: XXXms)
Filtre o logcat com "FireperfViews" e procure registros como estes:
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 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 contém seu app. No painel à esquerda, localize a seção Versões e monitorar e clique em Desempenho.
- Na guia Painel principal, role para baixo até a tabela de traces e clique na guia Traces personalizados. Nesta tabela, você vai encontrar os traces de código personalizados que adicionamos anteriormente, além de alguns traces prontos para uso, como o trace
_app_start
. - Encontre seus dois traces de código personalizados,
TestActivity-LoadTime
eTestFragment-LoadTime
. Clique na Duração de qualquer um deles 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).
- Também é possível conferir os dados de performance do trace de tela personalizado.
- Volte para a guia Painel principal, role para baixo até a tabela de traces e clique na guia Renderização de tela. Nesta tabela, você vai encontrar os traces de tela personalizados que adicionamos anteriormente, além de todos os traces de tela prontos para uso, como o
MainActivity
. - Encontre seu trace de tela personalizado,
MainActivity-TestFragment
. Clique no nome do trace para visualizar 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 um fragmento usando o Monitoramento de desempenho do Firebase.
Suas conquistas
- Você integrou o Monitoramento de desempenho do Firebase a um app de amostra
- Agora você entende o ciclo de vida do carregamento de visualização
- Você mediu o tempo de carregamento de uma atividade e de um fragmento adicionando traces de código personalizados.
- Você registrou frames lentos/congelados adicionando traces de tela personalizados com métricas personalizadas.
A seguir
O Firebase Performance oferece mais formas de medir o desempenho do seu app, além do trace personalizado. Ela mede automaticamente o tempo de inicialização do app e os dados de desempenho de apps em primeiro plano e em segundo plano. É hora de conferir 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 as solicitações de rede facilmente sem escrever uma linha sequer de código. Você pode tentar enviar algumas solicitações de rede pelo 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 explorar nossa base de código de código aberto para ver se consegue capturar essas métricas prontas para qualquer atividade/fragmento que faça parte do app? Fique à vontade para enviar o PR se quiser :-)
11. Aprendizado bônus
Entender o que está acontecendo durante o carregamento de uma atividade ajuda a entender melhor as características de desempenho do app. 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.