Os usuários esperam que os apps sejam responsivos e carreguem rapidamente. Um app com tempo de inicialização lento não atende a essa expectativa e pode decepcionar os usuários. Esse tipo de experiência ruim pode fazer com que o usuário dê uma classificação negativa ao seu app na Play Store ou até mesmo desista de usá-lo.
Esta página fornece informações para otimizar o tempo de inicialização do seu app, incluindo uma visão geral das partes internas do processo de lançamento, como criar um perfil do desempenho de inicialização, alguns problemas comuns e dicas para resolvê-los.
Entender os diferentes estados de inicialização do app
A inicialização do app pode ocorrer em um destes três estados: inicialização a frio, inicialização com estado salvo ou inicialização a quente. Cada estado afeta o tempo que leva para o app ficar visível para o usuário. Em uma inicialização a frio, o app é iniciado do zero. Nos outros estados, o sistema precisa levar o app que está em execução em segundo plano para o primeiro plano.
Recomendamos que você sempre otimize presumindo que se trate de uma inicialização a frio. Ao fazer isso, o desempenho de inicializações a quente e com estado salvo também pode melhorar.
Para otimizar seu app para uma inicialização rápida, vale a pena entender o que está acontecendo nos níveis do sistema e do app e como eles interagem em cada um desses estados.
Duas métricas importantes para determinar a inicialização do app são o tempo para exibição inicial (TTID, na sigla em inglês) e o tempo para exibição completa (TTFD, na sigla em inglês). O TTID é o tempo necessário para mostrar o primeiro frame, e o TTFD é o tempo que leva para o app se tornar totalmente interativo. Ambos são igualmente importantes, já que o TTID permite que o usuário saiba que o app está sendo carregado e o TTFD informa quando o app pode ser usado. Se um deles for muito longo, o usuário poderá sair do app antes mesmo de ele ser totalmente carregado.
Inicialização a frio
Uma inicialização a frio refere-se a um app que é inicializado do zero. Isso significa que, até esse início, o processo do sistema cria o processo do app. Inicializações a frio ocorrem em casos em que o app é iniciado pela primeira vez desde que o dispositivo foi inicializado ou quando o sistema o eliminou.
Esse tipo de inicialização representa o maior desafio para minimizar o tempo de inicialização, porque o sistema e o app têm mais trabalho a fazer do que nos outros estados de inicialização.
No início de uma inicialização a frio, o sistema tem estas três tarefas:
- Carregar e iniciar o app.
- Mostrar uma janela de inicialização em branco para o app imediatamente após o início.
- Criar o processo do app.
Assim que é criado pelo sistema, o processo do app fica responsável pelas próximas etapas:
- Criar o objeto de app.
- Iniciar a linha de execução principal.
- Criar a atividade principal.
- Inflar visualizações.
- Fazer o layout da tela.
- Executar o desenho inicial.
Quando o processo do app conclui o primeiro desenho, o processo do sistema substitui a janela de segundo plano exibida pela atividade principal. Nesse ponto, o usuário pode começar a usar o app.
A figura 1 mostra como os processos do sistema e do app transferem o trabalho entre si.

Problemas de desempenho podem surgir durante a criação do app e a criação da atividade.
Criação de apps
Quando o app é iniciado, a janela inicial em branco permanece na tela até o sistema concluir o desenho do app pela primeira vez. Nesse momento, o processo do sistema troca a janela inicial do app, permitindo que o usuário interaja com ele.
Se você substituir Application.onCreate()
no seu próprio app, o sistema
vai invocar o método onCreate()
no objeto do app. Em seguida, o app gera
a linha de execução principal (também conhecida como linha de execução de interface) e a encarrega de criar sua
atividade principal.
A partir desse ponto, os processos no nível do sistema e do app prosseguem de acordo com os estágios do ciclo de vida do app.
Criação da atividade
Depois que o processo do app cria sua atividade, ela executa as seguintes operações:
- Inicialização de valores.
- Chamada de construtores.
- Chama o método de callback, por exemplo,
Activity.onCreate()
, apropriado para o estado atual do ciclo de vida da atividade.
Normalmente, o método onCreate()
tem o maior impacto no tempo de carregamento,
já que executa o trabalho com maior overhead: carrega e infla
visualizações e inicializa os objetos necessários para a execução da atividade.
Inicialização com estado salvo
Uma inicialização com estado salvo abrange um subconjunto das operações que ocorrem durante uma inicialização a frio. Ao mesmo tempo, ela representa mais sobrecarga do que uma inicialização a quente. Há muitos estados em potencial que podem ser considerados inicializações com estado salvo, como:
O usuário sai do app e depois o reinicializa. O processo pode continuar em execução, mas o app precisa recriar a atividade do zero usando uma chamada para
onCreate()
.O sistema elimina seu app da memória e, em seguida, o usuário o reinicializa. O processo e a atividade precisam ser reiniciados, mas a tarefa pode se beneficiar um pouco do pacote de estado da instância salvo, transmitido para
onCreate()
.
Inicialização a quente
Uma inicialização a quente do app tem uma sobrecarga menor do que uma inicialização a frio. Em uma inicialização a quente, o sistema coloca sua atividade em primeiro plano. Se todas as atividades do app ainda estiverem na memória, ele poderá evitar a repetição da inicialização, a inflação de layouts e a renderização de objetos.
No entanto, se alguma memória for limpa em resposta a eventos de corte de memória, como
onTrimMemory()
, esses objetos precisarão ser recriados em resposta ao
evento de inicialização a quente.
Uma inicialização a quente exibe o mesmo comportamento que o do cenário de uma inicialização a frio: o processo do sistema mostra uma tela em branco até que o app termine de renderizar a atividade.

Como identificar a inicialização do app no Perfetto
Para depurar problemas de inicialização do app, determine exatamente o que está incluído na fase de inicialização. Para identificar toda a fase de inicialização do app no Perfetto, siga estas etapas:
No Perfetto, encontre a linha com a métrica derivada para inicialização de apps Android. Caso ela não esteja disponível, tente capturar um rastro usando o app de rastreamento do sistema no dispositivo.
Figura 3. Fração da métrica derivada para inicialização de apps Android no Perfetto. Clique na fração associada e pressione m para selecioná-la. Os colchetes aparecem ao redor da fração e indicam o tempo transcorrido. A duração também é mostrada na guia Seleção atual.
Fixe a linha "Android App Startups" clicando no ícone de fixação, que fica visível ao manter o ponteiro sobre a linha.
Role até a linha com o app em questão. Para abri-la, clique na primeira célula.
Aumente o zoom da linha de execução principal, geralmente localizado na parte de cima, pressionando w. Pressione s, a, d para diminuir o zoom, mover para a esquerda e mover para a direita, respectivamente.
Figura 4. Fração da métrica derivada para inicialização de apps Android ao lado da linha de execução principal do app. A fração da métrica derivada facilita a visualização exata do que está incluído na inicialização do app para que você possa continuar a depuração com mais detalhes.
Usar métricas para inspecionar e melhorar a inicialização
Para diagnosticar adequadamente a performance do tempo de inicialização, é possível rastrear métricas que mostram o tempo necessário para que o app seja iniciado. O Android oferece várias maneiras de mostrar que o app está com um problema e ajuda a diagnosticá-lo. O recurso "Android vitals" pode alertar que um problema está ocorrendo, e as ferramentas de diagnóstico podem ajudar a diagnosticar o problema.
Benefícios do uso de métricas de inicialização
O Android usa as métricas de tempo para exibição inicial (TTID) e tempo para exibição total (TTFD) para otimizar as inicializações de app a frio e com estado salvo. O Android Runtime (ART) usa os dados dessas métricas para pré-compilar de forma eficiente o código e otimizar futuras inicializações.
Inicializações mais rápidas levam a uma interação mais consistente com o app, o que reduz as instâncias de saída antecipada, a reinicialização da instância ou a saída para outro app.
Android vitals
O Android vitals pode ajudar a melhorar o desempenho do seu app mostrando alertas no Play Console quando o app demora demais para inicializar.
O Android vitals considera os seguintes tempos de inicialização do app excessivos:
- a inicialização a frio do app leva 5 segundos ou mais;
- a inicialização com estado salvo leva 2 segundos ou mais;
- a inicialização a quente leva 1,5 segundo ou mais.
O Android vitals usa a métrica Tempo para exibição inicial (TTID). Para conferir informações sobre como o Google Play coleta dados do Android vitals, consulte a documentação do Play Console.
Tempo para exibição inicial
O tempo para exibição inicial (TTID) é o tempo necessário para mostrar o primeiro frame
da interface do app. Essa métrica mede o tempo que um app leva para produzir
o primeiro frame, incluindo a inicialização do processo durante uma inicialização a frio, a criação de
atividades durante uma inicialização a frio ou com estado salvo e a exibição do primeiro frame. Manter
o TTID do app baixo ajuda a melhorar a experiência do usuário, permitindo que ele
inicie o app rapidamente. O TTID é informado automaticamente para cada app pelo framework do
Android. Ao otimizar a inicialização do app, recomendamos implementar
reportFullyDrawn
para receber informações até o TTFD.
O TTID é medido como um valor de tempo que representa o tempo total decorrido, incluindo a sequência de eventos abaixo:
- Início do processo
- Inicialização dos objetos
- Criação e inicialização da atividade
- Inflação do layout
- Exibição do app pela primeira vez
Extrair o TTID
Para encontrar o TTID, pesquise na ferramenta de linha de comando Logcat uma linha de saída
com um valor chamado Displayed
. Esse valor é o TTID e é semelhante
ao exemplo abaixo, em que o TTID é de 3s534ms:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
Para encontrar o TTID no Android Studio, desative os filtros na visualização do Logcat no
menu suspenso de filtros e encontre o tempo de Displayed
, conforme mostrado na Figura 5.
A desativação dos filtros é necessária porque o servidor do sistema, não o app
em si, atende a esse registro.

Displayed
no Logcat.A métrica Displayed
na saída do Logcat não captura necessariamente o
tempo até que todos os recursos sejam carregados e mostrados. Ela exclui
recursos que não são referenciados no arquivo de layout ou que o app cria como
parte da inicialização do objeto. Ela exclui esses recursos porque o carregamento deles
é um processo inline e não bloqueia a exibição inicial do app.
A linha Displayed
na saída do Logcat pode conter um outro campo para o
tempo total. Por exemplo:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
Nesse caso, a primeira medição de tempo é apenas da atividade que é desenhada
pela primeira vez. A medição do tempo total
começa no início do processo do app e pode
incluir outra atividade que é iniciada primeiro, mas que não é exibida na
tela. A medição de tempo total
só é mostrada quando há
uma diferença entre o tempo de inicialização da atividade individual e o total.
Recomendamos o uso do Logcat no Android Studio. No entanto, se você não estiver usando o Android
Studio, poderá medir o TTID executando o app com o comando
do gerenciador de atividades do shell do adb
. Confira um exemplo:
adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN
A métrica Displayed
aparece na saída do Logcat, como antes. A janela de
terminal mostra o seguinte:
Starting: Intent
Activity: com.example.app/.MainActivity
ThisTime: 2044
TotalTime: 2044
WaitTime: 2054
Complete
Os argumentos -c
e -a
são opcionais e permitem especificar <category>
e <action>
.
Tempo para exibição total
O tempo para exibição total (TTFD) é o tempo que leva para um app se tornar interativo para o usuário. Ele é informado como o tempo necessário para mostrar o primeiro frame da interface do app, bem como o conteúdo que é carregado de forma assíncrona após a exibição do frame inicial. Em geral, esse é o conteúdo principal carregado pela rede ou pelo disco, conforme informado pelo app. Em outras palavras, o TTFD inclui o TTID, bem como o tempo necessário para que o app possa ser usado. Manter o TTFD baixo ajuda a melhorar a experiência do usuário, permitindo uma interação rápida.
O sistema determina o TTID quando Choreographer
chama o método
onDraw()
da atividade e quando sabe que o chamado ocorreu pela primeira vez.
No entanto, o sistema não sabe quando determinar o TTFD, já que cada app
se comporta de maneira diferente. Para determinar o TTFD, o app precisa indicar ao sistema
o momento em que atinge o estado de exibição total.
Extrair o TTFD
Para encontrar o TTFD, indique o estado de exibição total chamando o método
reportFullyDrawn()
da ComponentActivity
. O
método reportFullyDrawn
informa quando o app está totalmente renderizado e em um estado
utilizável. O TTFD é o tempo decorrido entre o momento em que o sistema recebe a intent de inicialização
do app e o momento em que reportFullyDrawn()
é chamado. Se você não chamar
reportFullyDrawn()
, nenhum valor de TTFD será informado.
Para medir o TTFD, chame reportFullyDrawn()
depois de mostrar completamente a interface e
todos os dados. Não chame reportFullyDrawn()
antes que a janela da primeira
atividade seja mostrada pela primeira vez, conforme medido pelo sistema, porque ele
informa o tempo que o sistema mediu. Em outras palavras, se você chamar
reportFullyDrawn()
antes que o sistema detecte o TTID, ele vai informar que o
TTID e o TTFD têm o mesmo valor, e esse valor é o do TTID.
Quando você usa reportFullyDrawn()
, o Logcat mostra uma saída como o exemplo
abaixo, em que o TTFD é de 1s54ms:
system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms
A saída do Logcat pode incluir um tempo total
, conforme discutido em Tempo para
exibição inicial.
Se os tempos de exibição estiverem mais lentos do que o esperado, tente identificar os gargalos no processo de inicialização.
Você pode usar reportFullyDrawn()
para indicar o estado de exibição total em casos básicos,
quando você sabe que o estado de exibição total foi alcançado. No entanto, nos casos
em que as linhas de execução em segundo plano precisam concluir o trabalho antes que o estado de
exibição total seja alcançado, é necessário atrasar reportFullyDrawn()
para uma medição de
TTFD mais precisa. Para aprender a atrasar reportFullyDrawn()
, consulte a seção
abaixo.
Melhorar a precisão da marcação do tempo de inicialização
Se o app estiver executando o carregamento lento e a tela inicial não incluir
todos os recursos, como quando o app estiver buscando imagens da rede,
atrase a chamada de reportFullyDrawn
até que o app se torne
usável. Assim, você pode incluir o preenchimento da lista como parte do tempo de
comparação.
Por exemplo, se a interface contém uma lista dinâmica, como RecyclerView
ou uma lista lenta, talvez ela seja preenchida por uma tarefa em segundo plano concluída depois
que a lista for renderizada e, portanto, depois que a interface estiver marcada como totalmente renderizada.
Nesses casos, o preenchimento da lista não é incluído na comparação.
Para incluir o preenchimento da lista como parte da marcação do tempo de comparação, extraia o
FullyDrawnReporter
usando getFullyDrawnReporter()
e adicione um
informante no código do app. Libere o informante depois que a tarefa em segundo plano
terminar de preencher a lista.
O FullyDrawnReporter
não vai chamar o método reportFullyDrawn()
até que todos os
informantes adicionados sejam liberados. Ao adicionar um informante até que o processo em segundo plano
seja concluído, as marcações de tempo também vão incluir a quantidade de tempo necessária para preencher a
lista nos dados de marcação de tempo de inicialização. Isso não muda o comportamento do app para o
usuário, mas permite que os dados da marcação de tempo incluam o tempo necessário para preencher
a lista. O reportFullyDrawn()
não é chamado até que todas as tarefas sejam
concluídas, independente da ordem.
O exemplo abaixo mostra como é possível executar várias tarefas em segundo plano simultaneamente, cada uma registrando o próprio informante:
class MainActivity : ComponentActivity() { sealed interface ActivityState { data object LOADING : ActivityState data object LOADED : ActivityState } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { var activityState by remember { mutableStateOf(ActivityState.LOADING as ActivityState) } fullyDrawnReporter.addOnReportDrawnListener { activityState = ActivityState.LOADED } ReportFullyDrawnTheme { when(activityState) { is ActivityState.LOADING -> { // Display the loading UI. } is ActivityState.LOADED -> { // Display the full UI. } } } SideEffect { lifecycleScope.launch(Dispatchers.IO) { fullyDrawnReporter.addReporter() // Perform the background operation. fullyDrawnReporter.removeReporter() } lifecycleScope.launch(Dispatchers.IO) { fullyDrawnReporter.addReporter() // Perform the background operation. fullyDrawnReporter.removeReporter() } } } } }
public class MainActivity extends ComponentActivity { private FullyDrawnReporter fullyDrawnReporter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); fullyDrawnReporter = getFullyDrawnReporter(); fullyDrawnReporter.addOnReportDrawnListener(() -> { // Trigger the UI update. return Unit.INSTANCE; }); new Thread(new Runnable() { @Override public void run() { fullyDrawnReporter.addReporter(); // Do the background work. fullyDrawnReporter.removeReporter(); } }).start(); new Thread(new Runnable() { @Override public void run() { fullyDrawnReporter.addReporter(); // Do the background work. fullyDrawnReporter.removeReporter(); } }).start(); } }
Se o app usa o Jetpack Compose, você pode usar as APIs abaixo para indicar o estado de exibição total:
ReportDrawn
: indica que o elemento combinável está pronto para interação.ReportDrawnWhen
: usa um predicado, comolist.count > 0
, para indicar quando o elemento combinável está pronto para interação.ReportDrawnAfter
: usa um método de suspensão que, quando concluído, indica que o elemento combinável está pronto para interação.
Identificar gargalos
Para procurar gargalos, você pode usar o CPU Profiler do Android Studio. Para saber mais, consulte Inspecionar atividades de CPU com o CPU Profiler.
Você também pode conferir mais detalhes sobre possíveis gargalos usando o rastreamento inline nos
métodos onCreate()
dos seus apps e atividades. Para saber mais sobre o
rastreamento inline, consulte a documentação das funções Trace
e a visão geral
do rastreamento do sistema.
Resolver problemas comuns
Esta seção discute vários problemas que geralmente afetam o desempenho da inicialização dos apps. Esses problemas referem-se principalmente à inicialização de apps e objetos de atividade, bem como ao carregamento de telas.
Inicialização de apps pesados
O desempenho de inicialização pode ser afetado quando seu código modifica o objeto Application
e executa um trabalho pesado ou lógica complexa ao inicializar esse objeto. Seu app
poderá perder tempo durante a inicialização se as subclasses Application
realizarem
inicializações que ainda não precisam ser feitas.
Algumas inicializações podem ser completamente desnecessárias, como ao inicializar informações de estado para a atividade principal quando o app é realmente iniciado em resposta a uma intent. Com uma intent, o app usa apenas um subconjunto dos dados de estado inicializados anteriormente.
Outros desafios durante a inicialização do app incluem eventos de coleta de lixo impactantes ou numerosos, ou E/S de disco que aconteçam simultaneamente com a inicialização, bloqueando ainda mais o processo de inicialização. A coleta de lixo é especialmente uma consideração no tempo de execução do Dalvik. O Android Runtime (ART) executa a coleta de lixo simultaneamente, minimizando o impacto dessa operação.
Diagnosticar o problema
Você pode usar o rastreamento de métodos ou in-line para tentar diagnosticar o problema.
Rastreamento de métodos
A execução do CPU Profiler revela que o método
callApplicationOnCreate()
finalmente chama seu método com.example.customApplication.onCreate
. Se a ferramenta mostrar que esses
métodos estão demorando muito para terminar a execução,
continue investigando para descobrir qual trabalho está ocorrendo.
Rastreamento in-line
Use o rastreamento inline para investigar as causas prováveis, incluindo as seguintes:
- A função
onCreate()
inicial do app. - Quaisquer objetos singleton que seu app inicializa.
- E/S de disco, desserialização ou loop apertado que possa estar ocorrendo durante o gargalo.
Soluções para o problema
Se o problema está nas inicializações desnecessárias ou na E/S de disco, a solução é a inicialização lenta. Em outras palavras, inicialize apenas os objetos imediatamente necessários. Em vez de criar objetos estáticos globais, mude para um padrão Singleton, em que o app inicializa objetos apenas na primeira vez que eles são necessários.
Além disso, você pode usar um framework de injeção de dependências como Hilt, que cria objetos e dependências quando injetados pela primeira vez.
Se o app usa provedores de conteúdo para iniciar componentes de apps na inicialização, considere usar a biblioteca App Startup.
Inicialização de atividades pesadas
A criação de atividades geralmente envolve muito trabalho com sobrecarga. Muitas vezes, há oportunidades de otimizar esse trabalho para melhorar o desempenho. Esses problemas comuns incluem o seguinte:
- Inflar layouts grandes ou complexos.
- Bloquear desenho de tela em disco ou E/S de rede.
- Carregar e decodificar bitmaps.
- Como fazer varredura de objetos
VectorDrawable
. - Inicializar outros subsistemas da atividade.
Diagnosticar o problema
Nesse caso também, o rastreamento de métodos e inline podem ser úteis.
Rastreamento de métodos
Ao usar o CPU Profiler, preste atenção aos construtores de subclasse
Application
e aos métodos com.example.customApplication.onCreate()
.
Se a ferramenta mostrar que esses métodos estão demorando muito para terminar a execução, continue investigando para descobrir qual trabalho está ocorrendo.
Rastreamento in-line
Use o rastreamento inline para investigar as causas prováveis, incluindo as seguintes:
- A função
onCreate()
inicial do app. - Qualquer objeto singleton global inicializado.
- E/S de disco, desserialização ou loop apertado que possa estar ocorrendo durante o gargalo.
Soluções para o problema
Há muitos gargalos em potencial, mas dois problemas e soluções comuns são os seguintes:
- Quanto maior for sua hierarquia de visualizações, mais tempo o app levará para inflá-la. Você
pode executar duas etapas para solucionar esse problema:
- Nivelar sua hierarquia de visualizações, reduzindo layouts redundantes ou aninhados.
- Não infle partes da interface que não precisam estar visíveis durante a inicialização.
Em vez disso, use um objeto
ViewStub
como marcador de posição para sub-hierarquias que o app pode inflar em um momento mais adequado.
- Colocar toda a inicialização de recursos na linha de execução principal também pode deixar a
inicialização lenta. Você pode solucionar esse problema desta forma:
- Mova toda a inicialização de recursos para outra linha de execução para que o app possa inicializá-los lentamente.
- Permita que o app carregue e mostre as visualizações e só depois atualize as propriedades visuais que dependem de bitmaps e outros recursos.
Telas de apresentação personalizadas
Talvez você note um tempo extra durante a inicialização se tiver usado um dos seguintes métodos para implementar uma tela de apresentação personalizada no Android 11 (nível 30 da API) ou versões anteriores:
- O atributo de tema
windowDisablePreview
para desativar a tela em branco inicial mostrada pelo sistema durante a inicialização. - Uso de um
Activity
dedicado.
No Android 12 e versões mais recentes, é necessário migrar para a API SplashScreen
.
Ela possibilita um tempo de inicialização mais rápido e também um ajuste de tela de apresentação destas
formas:
- Defina um tema para mudar a aparência da tela de apresentação.
- Controle por quanto tempo a tela de apresentação é mostrada com
windowSplashScreenAnimationDuration
. - Personalize a animação da tela de apresentação e processe corretamente a animação para dispensá-la.
Além disso, a biblioteca de compatibilidade faz o backport da API SplashScreen
para ativar
a compatibilidade com versões anteriores e criar uma aparência consistente para mostrar a
tela de apresentação em todas as versões do Android.
Para saber mais, consulte o guia para migrar a tela de apresentação.
Recomendados para você
Renderização lenta
Plan to create quality apps and features from the start by understanding best practices and requirements.
Capturar métricas de Macrobenchmark
Plan to create quality apps and features from the start by understanding best practices and requirements.
Criar perfis de referência
Plan to create quality apps and features from the start by understanding best practices and requirements.