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 inclui 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 ela seja completamente desenhada na tela. Telas lentas e travadas 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 maneira imediata?
O Monitoramento de desempenho do Firebase captura automaticamente alguns dados de desempenho assim que é instalado, como o tempo de inicialização do app (ou seja, o tempo de carregamento da primeira atividade) e o desempenho 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 visualizações personalizadas próprias para casos de uso mais complexos. Por isso, é útil entender como medir o tempo de carregamento e o desempenho de renderização de tela de atividades e fragmentos instrumentando traces de código personalizados no app. É fácil estender este codelab para medir o desempenho de 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 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 registrar telas lentas/congeladas
- Como ver as métricas coletadas no console do Firebase
O que é necessário
- Android Studio 4.0 ou versões mais recentes
- 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 amostra 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 em 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/Ajuda > Verificar atualizações para garantir que você esteja usando as versões mais recentes do Android Studio e do Firebase Assistente.
- Selecione Ferramentas > 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 no botão para criar um projeto e insira um nome (por exemplo,
Measure Performance Codelab
). - Clique em Continuar.
- Se solicitado, leia e aceite os Termos do Firebase e clique em Continuar.
- (Opcional) Ative a assistência de IA no console do Firebase (chamada de "Gemini no Firebase").
- Neste codelab, você não precisa do Google Analytics. Portanto, desative a opção do Google Analytics.
- Em seguida, uma caixa de diálogo vai aparecer para Conectar seu novo app do Firebase ao projeto do Android Studio.
- De volta ao Android Studio, no painel Assistente, você vai ver a confirmação de que seu 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 vai aparecer para Aceitar mudanças. 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 do Android Studio, indicando que todas as dependências foram configuradas corretamente.
Como uma 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. Executar o app
Se você tiver integrado o app ao SDK do Monitoramento de desempenho, o projeto será compilado. No Android Studio, clique em Executar > Executar "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, assim:
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. Entender 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 tempo desde a criação do objeto de atividade até que o primeiro frame seja completamente desenhado na tela. É quando o usuário vê a interface completa da atividade pela primeira vez. Para medir se o app foi totalmente renderizado, 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 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 a duração 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 desde que o fragmento é anexado à atividade host até que o primeiro frame da visualização do fragmento seja completamente desenhado 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 quanto tempo de atraso no carregamento inicial 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 Activity assim que o objeto Activity 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 receba 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 a performance dele. 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 e filtre o logcat com "Métrica de rastreamento de geração de registros". Toque no botão
LOAD ACTIVITY
e procure registros como este:
I/FirebasePerformance: Logging trace metric: TestActivity-LoadTime (duration: XXXms)
🎉 Parabéns! Você mediu com sucesso 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 do FirstDrawListener
Na seção acima, registramos um FirstDrawListener
. A finalidade de 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 desenhada. Em seguida, ele encapsula o resultado para fornecer dois callbacks de utilidade, onDrawingStart()
e onDrawingFinish()
.
O código completo do FirstDrawListener
pode ser encontrado no código-fonte do codelab.
6. Medir o tempo de carregamento de um fragmento
Medir o tempo de carregamento de um Fragment é semelhante a como fazemos isso para uma Activity, mas com algumas pequenas diferenças. Vamos instrumentar um trace de código personalizado:
- Substitua o callback
onAttach()
e comece a gravar seufragmentLoadTrace
. Vamos chamar esse rastreamento deTest-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, de maneira semelhante ao exemplo de atividade, pare 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 e filtre o logcat com "Métrica de rastreamento de geração de registros". 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 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 da 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 Firebase Performance Monitoring captura automaticamente frames lentos/congelados de uma atividade apenas 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.
Com base na motivação da classe AppStateMonitor
(que faz parte do SDK do Monitoramento de desempenho e é responsável por gravar rastreamentos de tela para atividades), 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 fornece duas APIs públicas:
recordScreenTrace()
: inicia a gravação de um trace de tela.sendScreenTrace()
: interrompe a gravação de um rastreamento de tela e anexa métricas personalizadas para registrar as contagens de frames totais, lentos e congelados.
Ao anexar essas métricas personalizadas, os traces de tela para Fragments podem ser processados da mesma forma que os traces de tela para uma Activity e podem ser exibidos junto 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
// 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
FragmentLifecycleCallbacks
e substitua os callbacksonFragmentAttached()
eonFragmentDetached()
. Fizemos isso para você. Você precisa iniciar a gravação de rastreamentos de tela no callbackonFragmentAttached()
e interromper 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 inferior.
Filtre o logcat com Métrica de rastreamento de registros e procure registros como os abaixo:
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 com sucesso 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 rastreamento.
Outra opção é selecionar o projeto que tem seu app no console do Firebase. No painel à esquerda, localize a seção Lançamento e monitoramento e clique em Performance.
- Na guia principal Painel, role a página 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 antes, além de alguns traces prontos para uso, como o trace
_app_start
. - Encontre seus dois traces de código personalizado,
TestActivity-LoadTime
eTestFragment-LoadTime
. Clique em Duração em 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).
- Você também pode conferir os dados de performance do rastreamento de tela personalizado.
- Volte para a guia principal Painel, role para baixo até a tabela de rastreamentos e clique na guia Renderização da tela. Nesta tabela, você vai encontrar os rastreamentos de tela personalizados que adicionamos antes, além de rastreamentos de tela prontos para uso, como o rastreamento
MainActivity
. - Encontre seu rastreamento de 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 com sucesso o tempo de carregamento e o desempenho de renderização da tela de uma atividade e de 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 de um fragmento adicionando traces de código personalizados.
- Você registrou frames lentos/congelados ao adicionar 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, o desempenho do app em primeiro plano e em segundo plano. Agora é 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. Assim, é possível instrumentar facilmente solicitações de rede sem 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 explorar nossa base de código de código aberto para ver se é possível capturar essas métricas imediatamente para qualquer atividade/fragmento que faça parte do app. Se quiser, pode enviar o PR :-)
11. Aprendizagem extra
Entender o que acontece durante o carregamento de uma atividade ajuda a entender melhor as características de desempenho do seu 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.