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 interface 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 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 (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.
- Compreensão da 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 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 para este codelab. Isso 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
Caso você não tenha o git na sua máquina, também é possível fazer o download do código diretamente no 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 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 seu 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 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 seu 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 encontrar a mensagem de êxito no painel do Assistente no Android Studio informando que todas as dependências estão 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 > Execute "app" para criar e executar o app no dispositivo/emulador Android conectado.
O app tem dois botões que levam a uma atividade e um fragmento correspondentes, desta forma:
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 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é 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 quando 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 trace 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 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 abaixo para mais detalhes sobreFirstDrawListener
e o que pode afetar o desempenho dela). Registre oFirstDrawListener
ao final do callbackonCreate()
da atividade. Interrompa 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 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 do FirstDrawListener
é medir quando o primeiro frame começou e terminou de ser desenhado.
Ela implementa ViewTreeObserver.OnDrawListener
e substitui o callback onDraw()
que é invocado quando a árvore de visualização está prestes a ser desenhada. Em seguida, ele encapsula o resultado para fornecer dois callbacks de utilitários, 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 gravarfragmentLoadTrace
. 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 é anexado à atividade 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 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. Depois, filtre o Logcat com "Métrica de trace do Logging". 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 os dados ao Monitoramento de desempenho do Firebase. Veremos a métrica gravada no Console do Firebase mais adiante neste codelab.
7. Compreensão da renderização de tela e o que é um frame lento/congelado
Renderização da interface é o ato de gerar um frame do seu app e exibi-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, frames congelados são frames de interface que levam mais de 700 ms para serem renderizados. Esse atraso é um problema porque seu 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 para 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 vinculada ao callback do ciclo de vida de 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 traces de tela para fragmentos podem ser processados da mesma forma que os traces de tela de uma atividade e podem ser exibidos com outros traces de renderização de tela no painel Desempenho 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 por "Logging trace metric" e depois procure por 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. 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 contém seu aplicativo. No painel esquerdo, localize a seção Versões e Monitorar e em Desempenho.
- Na guia principal Painel, 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
_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).
- Também é possível visualizar os dados de desempenho do seu trace de tela personalizado.
- Volte para a guia principal do Painel, 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 dos traces de tela prontos para uso, como
MainActivity
. - Encontre seu trace 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ções
- 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 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, você pode instrumentar facilmente as solicitações de rede sem escrever uma única linha de código. Tente enviar algumas solicitações de rede do seu app e encontre 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 consegue 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.