Durante a inicialização do app, ele causa a primeira impressão nos usuários. É necessário que a inicialização seja rápida para carregar e mostrar informações que o usuário precisa para usar o app. Se ela demorar muito, os usuários poderão sair por estarem esperando por muito tempo.
Recomendamos usar a biblioteca Macrobenchmark para avaliar a inicialização. A biblioteca oferece uma visão geral e rastreamentos detalhados do sistema para mostrar exatamente o que está acontecendo durante a inicialização.
Os rastreamentos do sistema fornecem informações úteis sobre o que está acontecendo no dispositivo. Isso permite entender o que o app faz durante a inicialização e identificar as possíveis áreas de otimização.
Para analisar a inicialização do app, siga estas etapas:
- Configure um ambiente para gravar rastreamentos de inicialização do app.
- Entenda os rastreamentos do sistema.
- Navegue em um relatório de rastreamento usando os Android Studio Profilers ou o Perfetto (em inglês).
Etapas para analisar e otimizar a inicialização
Durante a inicialização, os apps geralmente precisam carregar recursos específicos que são essenciais para os usuários finais. Recursos não essenciais podem aguardar o carregamento depois da conclusão da inicialização.
Para melhorar o desempenho, siga estas etapas:
Use a biblioteca Macrobenchmark para medir o tempo gasto por cada operação e identificar blocos que levam muito tempo para serem concluídos.
Confirme se a operação com uso intensivo de recursos é indispensável para a inicialização do app. Se a operação puder aguardar até o app ser totalmente carregado, isso poderá minimizar as restrições de recursos na inicialização.
Garanta que essa operação seja executada na inicialização do app. Muitas vezes, operações desnecessárias podem ser chamadas do código legado ou de bibliotecas de terceiros.
Se possível, mova operações de longa duração para o segundo plano. Os processos em segundo plano ainda podem afetar o uso da CPU durante a inicialização.
Depois de investigar a operação, você pode decidir entre o tempo necessário para carregar e a necessidade de incluí-la na inicialização do app. É importante incluir o potencial de regressão ou alterações interruptivas ao mudar o fluxo de trabalho do app.
Otimize e meça de novo até chegar a um tempo de inicialização satisfatório para o app. Para saber mais, consulte Usar métricas para detectar e diagnosticar problemas.
Medir e analisar o tempo gasto nas principais operações
Quando você tiver um rastreamento de inicialização completo do app, observe-o e meça a duração
das principais operações, como bindApplication
ou activityStart
. Recomendamos
o uso do Perfetto ou dos Android
Studio Profilers para analisar esses rastreamentos.
Observe o tempo total da inicialização do app para identificar operações que:
- gastem muito tempo e possam ser otimizadas. Cada milissegundo conta para o
desempenho. Por exemplo, procure
tempos de exibição
Choreographer
, tempos de inflação de layout, tempos de carregamento da biblioteca, transaçõesBinder
ou tempos de carregamento de recursos. Para começar, analise todas as operações que levam mais de 20 ms; - bloqueiem a linha de execução principal. Para saber mais, consulte Navegar em um relatório do Systrace;
- não tenham a execução necessária na inicialização;
- possam aguardar até que o primeiro frame seja renderizado.
Investigue cada um desses rastros para encontrar lacunas de desempenho.
Identificar operações caras na linha de execução principal
A prática recomendada é manter as operações caras, como as de E/S de arquivos e as de acesso
à rede, fora da linha de execução principal. Isso é igualmente importante durante a inicialização do app,
porque operações caras na linha de execução principal podem fazer com que o app não responda
e podem atrasar outras operações importantes.
A StrictMode.ThreadPolicy
pode
ajudar a identificar casos em que operações caras estão acontecendo na linha de execução principal.
É recomendável ativar a classe StrictMode
em
builds de depuração para identificar problemas o quanto antes, conforme mostrado no
exemplo abaixo:
Kotlin
class MyApplication : Application() { override fun onCreate() { super.onCreate() ... if (BuildConfig.DEBUG) StrictMode.setThreadPolicy( StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyDeath() .build() ) ... } }
Java
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); ... if(BuildConfig.DEBUG) { StrictMode.setThreadPolicy( new StrictMode.ThreadPolicy.Builder() .detectAll() .penaltyDeath() .build() ); } ... } }
O uso da StrictMode.ThreadPolicy
ativa a política de linha de execução em todos os builds de depuração
e causa uma falha no app sempre que violações da política de linha de execução são detectadas, o que
faz com que seja fácil encontrar violações da política em linhas de execução.
TTID e TTFD
Para conferir o tempo que o app leva para produzir o primeiro frame, meça o tempo para exibição inicial (TTID, na sigla em inglês). No entanto, isso não reflete necessariamente o tempo até o usuário começar a interagir com o app. A métrica tempo para exibição total (TTFD, na sigla em inglês) é mais útil para medir e otimizar os caminhos de código necessários para ter um estado totalmente utilizável do app.
Para conferir estratégias de geração de relatórios quando a interface do app está totalmente renderizada, consulte Melhorar a precisão da marcação do tempo de inicialização.
Otimize para TTID e TTFD, porque ambos são importantes nas respectivas áreas. Um TTID baixo ajuda o usuário a saber que o app está sendo iniciado. Já manter o TTFD baixo é importante para garantir que o usuário possa começar a interagir com o app rapidamente.
Analisar o estado geral da linha de execução
Selecione o tempo de inicialização do app e observe as frações gerais da linha de execução. A linha de execução principal precisa ser responsiva o tempo todo.
Ferramentas como o Android Studio Profiler e Perfetto (em inglês) fornecem uma visão geral detalhada da linha de execução principal e de quanto tempo é gasto cada etapa. Para saber mais sobre a visualização de rastros do Perfeito, consulte IU do Perfetto (link em inglês) na documentação do Google Cloud.
Identificar os principais trechos do estado de suspensão da linha de execução principal
Se muito tempo é gasto em suspensão, é provável que a linha de execução principal do app esteja aguardando a conclusão do trabalho. Se você tem um app com várias linhas de execução, identifique aquela em que a principal está aguardando e otimize essas operações. Isso também ajuda a garantir que não haja contenção de bloqueio desnecessária causando atrasos no caminho crítico.
Reduzir o bloqueio das principais linhas de execução e da suspensão ininterrupta
Procure cada instância da linha de execução principal que entra em um estado bloqueado. O Perfetto e o Studio Profiler mostram isso com um indicador laranja na linha do tempo do estado da linha de execução. Identifique as operações, verifique se elas são esperadas ou podem ser evitadas e otimize o que for necessário.
A suspensão que pode ser interrompida e está relacionada a pedidos de veiculação pode ser uma boa oportunidade de melhoria. Outros processos que fazem pedido de veiculação, mesmo que não sejam apps não relacionados, podem lidar com o pedido que o app principal está fazendo.
Melhorar o tempo de inicialização
Depois de identificar uma oportunidade de otimização, teste algumas possíveis soluções para melhorar os tempos de inicialização:
- Carregue conteúdo de maneira lenta e assíncrona para acelerar o TTID.
- Minimize as funções de chamada que fazem chamadas de binder. Se elas forem inevitáveis, confira se você está otimizando essas chamadas armazenando valores em cache em vez de repeti-las ou de mover o trabalho sem bloqueio para linhas de execução em segundo plano.
- Para que a inicialização do app apareça mais rapidamente, mostre ao usuário algo que precise do mínimo de renderização o mais rápido possível até que o restante da tela termine de carregar.
- Crie e adicione um perfil de inicialização ao app.
- Use a biblioteca App Startup do Jetpack para simplificar a inicialização dos componentes durante a inicialização do app.
Analisar o desempenho da interface
A inicialização do app inclui uma tela de apresentação e o tempo de carregamento da página inicial. Se quiser otimizar a inicialização do app, você poderá inspecionar os rastreamentos até entender o tempo necessário para que a interface seja renderizada.
Limitar o trabalho na inicialização
O carregamento de alguns frames pode levar mais tempo do que outros. Essas exibições são consideradas pesadas para o app.
Para otimizar a inicialização, siga estas etapas:
- Priorize transmissões de layout lentas para fazer melhorias.
- Investigue cada aviso do Perfetto e os alertas do Systrace adicionando eventos de rastreamento personalizados para reduzir atrasos e exibições pesadas.
Medir dados de frame
Há várias maneiras de medir dados de frame. Estes são os cinco principais métodos de coleta:
- Coleta local usando
dumpsys gfxinfo
: nem todos os frames observados nos dados do dumpsys são responsáveis pela renderização lenta do app ou têm um impacto para os usuários finais. No entanto, essa é uma boa medida em diferentes ciclos de lançamento para entender a tendência geral de desempenho. Para saber mais sobre como usargfxinfo
eframestats
para integrar a medição de desempenho da interface às suas práticas de teste, consulte Conceitos básicos para testar apps Android. - Coleta de campos usando JankStats: colete tempos de renderização de frames de partes específicas do app com a biblioteca JankStats para gravar e analisar o dados.
- Em testes que usam Macrobenchmark (Perfetto em segundo plano).
- Perfetto (em inglês) FrameTimeline: No Android 12 (nível 31 da API), é possível coletar a linha do tempo de frames métricas de um rastro do Perfetto para descobrir qual trabalho está causando o descarte do frame. Essa pode ser a primeira etapa para diagnosticar o motivo do descarte.
- Android Studio Profiler para detecção de instabilidade.
Verificar o tempo de carregamento da atividade principal
A atividade principal do app pode conter uma grande quantidade de informações
carregadas de várias fontes. Confira o layout da Activity
inicial e
observe o método Choreographer.onDraw
da
atividade inicial.
- Use
reportFullyDrawn
para informar ao sistema que o app foi completamente renderizado para fins de otimização. - Meça atividades e inicializações de apps usando
StartupTimingMetric
com a biblioteca Macrobenchmark. - Observe os descartes de frames.
- Identifique layouts que demoram para serem renderizados ou medidos.
- Identifique os recursos que estão demorando muito para carregar.
- Identifique layouts desnecessários que são inflados durante a inicialização.
Considere estas possíveis soluções para otimizar o tempo de carregamento da atividade principal:
- Deixe o layout inicial o mais básico possível. Para saber mais, consulte Otimizar hierarquias de layout.
- Adicione pontos de rastreamento personalizados para fornecer mais informações sobre frames descartados e layouts complexos.
- Minimize o número e o tamanho dos recursos de bitmap carregados durante a inicialização.
Use
ViewStub
quando os layouts não ficarem imediatamenteVISIBLE
(visíveis). AViewStub
é uma visualização invisível de tamanho zero que pode ser usada para inflar lentamente recursos de layout no momento da execução. Para saber mais, consulteViewStub
.Se você estiver usando o Jetpack Compose, poderá ter um comportamento semelhante ao
ViewStub
usando o estado para adiar o carregamento de alguns componentes:var shouldLoad by remember {mutableStateOf(false)} if (shouldLoad) { MyComposable() }
Carregue os elementos combináveis dentro do bloco condicional modificando
shouldLoad
:LaunchedEffect(Unit) { shouldLoad = true }
Isso aciona uma recomposição que inclui o código dentro do bloco condicional no primeiro snippet.
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Capturar métricas de Macrobenchmark
- Visão geral da avaliação do desempenho do app * Frames congelados