A otimização da memória é essencial para garantir um desempenho tranquilo, evitar falhas de apps e manter a estabilidade do sistema e a integridade da plataforma. Embora o uso de memória precise ser monitorado e otimizado em todos os apps, os apps de conteúdo para dispositivos de TV têm desafios específicos que diferem dos apps Android típicos para dispositivos móveis.
O alto consumo de memória pode causar problemas com o comportamento do app e do sistema, incluindo:
- O próprio app pode ficar lento ou apresentar atrasos. No pior caso, ele pode ser encerrado.
- Serviços do sistema visíveis ao usuário (controle de volume, painel de configurações de imagem, Google Assistente etc.) ficam muito lentos ou podem não funcionar.
- O processo daemon do low memory killer (LMK) pode reagir à alta pressão de memória encerrando os processos menos essenciais. Depois, esses componentes podem ser reiniciados logo em seguida, causando picos de mais disputa de recursos, o que pode afetar diretamente o aplicativo em primeiro plano.
- A transição para o iniciador pode ser significativamente atrasada e deixar o aplicativo em primeiro plano sem resposta até que a transição seja concluída.
- O sistema pode começar a usar a recuperação direta, pausando temporariamente a execução de uma linha de execução enquanto aguarda a alocação de memória. Isso pode acontecer com qualquer linha de execução, como a principal ou as relacionadas a codecs, causando potencialmente quedas de frames de áudio e vídeo e falhas na interface.
Considerações sobre memória em dispositivos de TV
Os dispositivos de TV geralmente têm muito menos memória do que smartphones ou tablets. Por exemplo, uma configuração que podemos ver na TV é 1 GB de RAM e resolução de vídeo de 1080p. Ao mesmo tempo, a maioria dos apps de TV tem recursos semelhantes e, portanto, implementação e desafios comuns. Essas duas situações apresentam problemas que não são vistos em outros tipos de dispositivos e apps:
- Os apps de TV de mídia geralmente são compostos de visualizações de imagens em grade e imagens de plano de fundo em tela cheia, que exigem o carregamento de muitas imagens na memória em um curto período.
- Os apps de TV reproduzem streams multimídia que exigem a alocação de uma certa quantidade de memória para reproduzir vídeo e áudio e precisam de buffers de mídia consideráveis para garantir uma reprodução sem problemas.
- Outros recursos de mídia (busca, mudança de episódio, mudança de faixa de áudio etc.) podem aumentar a pressão na memória se não forem implementados corretamente.
Entenda os dispositivos de TV
Este guia se concentra principalmente no uso da memória do app e nas metas de memória para dispositivos com pouca RAM.
Em dispositivos de TV, considere estas características:
- Memória do dispositivo: a quantidade de memória de acesso aleatório (RAM) instalada no dispositivo.
- Resolução da interface do dispositivo: a resolução que o dispositivo usa para renderizar a interface do SO e dos aplicativos. Normalmente, ela é menor que a resolução de vídeo do dispositivo.
- Resolução de vídeo: a resolução máxima em que o dispositivo pode reproduzir vídeos.
Isso leva à categorização de diferentes tipos de dispositivos e como a memória deve ser usada por eles.
Resumo dos dispositivos de TV
| Memória do dispositivo | Resolução de vídeo do dispositivo | Resolução da interface do dispositivo | isLowRAMDevice() |
|---|---|---|---|
| 1 GB | 1080p | 720p | Sim |
| 1,5 GB | 2160p | 1080p | Sim |
| ≥1,5 GB | 1080p | 720p ou 1080p | Não* |
| ≥2 GB | 2160p | 1080p | Não* |
Dispositivos de TV com pouca memória RAM
Esses dispositivos estão em uma situação de memória limitada e vão informar
ActivityManager.isLowRAMDevice()
como verdadeiro. Os aplicativos executados em dispositivos de TV com pouca RAM precisam implementar medidas adicionais de controle de memória.
Consideramos que os dispositivos com as seguintes características se enquadram nessa categoria:
- Dispositivos de 1 GB: 1 GB de RAM, resolução de interface 720p/HD (1280x720), resolução de vídeo 1080p/FullHD (1920x1080)
- Dispositivos de 1,5 GB: 1,5 GB de RAM, resolução de interface de usuário 1080p/FullHD (1920x1080), resolução de vídeo 2160p/UltraHD/4K (3840x2160)
- Outras situações em que o OEM definiu a flag
ActivityManager.isLowRAMDevice()devido a restrições de memória adicionais.
Dispositivos de TV comuns
Esses dispositivos não sofrem uma situação de pressão de memória tão significativa. Consideramos que esses dispositivos têm as seguintes características:
- ≥1,5 GB de RAM, interface de 720p ou 1080p e resolução de vídeo de 1080p
- ≥2 GB de RAM, interface de 1080p e resolução de vídeo de 1080p ou 2160p
Isso não significa que os apps não precisam se preocupar com o uso da memória nesses dispositivos, já que alguns erros específicos ainda podem esgotar a memória disponível e ter um desempenho ruim.
Metas de memória em dispositivos de TV com pouca RAM
Ao medir a memória nesses dispositivos, recomendamos muito monitorar todas as seções da memória usando o Memory Profiler do Android Studio. Os apps de TV precisam criar um perfil do uso da memória e trabalhar para colocar as categorias abaixo dos limites definidos nesta seção.

Na seção Como a memória é contada, você encontra uma explicação detalhada dos números de memória informados. Para a definição de limites para apps de TV, vamos nos concentrar em três categorias de memória:
- Anônima + troca: composta por memória de alocação Java + nativa + de pilha no Android Studio.
- Gráficos: informados diretamente na ferramenta do criador de perfil. Geralmente composto de texturas gráficas.
- Arquivo: informado como "Código" + "Outros" no Android Studio.
Com essas definições, a tabela a seguir indica o valor máximo que cada tipo de grupo de memória deve usar:
| Tipo de memória | Purpose | Metas de uso (1 GB) |
|---|---|---|
| Anônimo + troca (Java + nativo + pilha) | Usado para alocações, buffers de mídia, variáveis e outras tarefas que exigem muita memória. | < 160 MB |
| Gráficos | Usado pela GPU para texturas e buffers relacionados à exibição. | 30 a 40 MB |
| Arquivo | Usado para páginas de código e arquivos na memória. | 60 a 80 MB |
A memória total máxima (Anon+Swap + Gráficos + Arquivo) não pode exceder o seguinte:
- 280 MB de uso da memória total (Anon+Swap + Graphics + File) para dispositivos de 1 GB de RAM baixa.
É altamente recomendável não exceder:
- 200 MB de uso da memória em (Anon+Swap + Graphics).
Memória de arquivo
Como orientação geral para memória com suporte de arquivo, saiba que:
- Em geral, a memória de arquivos é bem processada pelo gerenciamento de memória do SO.
- No momento, não consideramos que ele seja uma causa principal de pressão de memória.
No entanto, ao lidar com a memória de arquivo em geral:
- Não inclua bibliotecas não usadas no build e, quando possível, use pequenos subconjuntos de bibliotecas em vez das completas.
- Não deixe arquivos grandes abertos na memória. Libere-os assim que terminar de usar.
- Minimize o tamanho do código compilado para classes Java e Kotlin. Consulte o guia Reduzir, ofuscar e otimizar o app.
Recomendações específicas de TV
Esta seção oferece recomendações específicas para otimizar o uso da memória em dispositivos de TV.
Memória gráfica
Use formatos e resoluções de imagem adequados.
- Não carregue imagens com resolução maior do que a da interface do dispositivo. Por exemplo, imagens em 1080p precisam ser reduzidas para 720p em um dispositivo de interface de usuário de 720p.
- Use bitmaps com suporte de hardware quando possível.
- Em bibliotecas como o Glide, ative o recurso
Downsampler.ALLOW_HARDWARE_CONFIGque está desativado por padrão. Isso evita a duplicação de bitmaps, que, de outra forma, estariam na memória gráfica e na memória anônima.
- Em bibliotecas como o Glide, ative o recurso
- Evite renderizações intermediárias e novas renderizações
- Eles podem ser identificados com o Android GPU Inspector:
- Na seção "Texturas", procure imagens que sejam etapas para a renderização final, em vez de apenas os elementos que as formam. Isso geralmente é chamado de "renderização intermediária".
- Em aplicativos do SDK do Android, é possível remover esses elementos usando a
flag de layout
forceHasOverlappedRendering:falsepara desativar renderizações intermediárias desse layout. - Consulte Evitar renderizações sobrepostas em renderizações sobrepostas como um ótimo recurso.
- Evite carregar imagens de marcador de posição quando possível. Use
@android:color/ou@colorpara texturas de marcador de posição. - Evite compor várias imagens no dispositivo quando a composição puder ser feita off-line. Prefira carregar imagens independentes em vez de fazer composição de imagens baixadas
- Siga o guia Como gerenciar bitmaps para lidar melhor com bitmaps.
Memória Anon+Swap
Anon+Swap é composto por alocações nativas, Java e de pilha no criador de perfil de memória do Android Studio. Use
ActivityManager.isLowMemoryDevice()
para verificar se o dispositivo tem restrição de memória e se adaptar a essa situação
seguindo estas diretrizes.
- Mídia:
- Especifique um tamanho variável para os buffers de mídia dependendo da RAM do dispositivo e da resolução de reprodução de vídeo. Isso deve representar 1 minuto
de reprodução de vídeo:
- 40 a 60 MB para 1 GB / 1080p
- 60 a 80 MB para 1,5 GB / 1080p
- 80 a 100 MB para 1,5 GB / 2160p
- 100 a 120 MB para 2 GB / 2160p
- Liberação de alocações de memória de mídia livre ao mudar um episódio para evitar aumentos na quantidade total de memória anônima.
- Libere e pare os recursos de mídia imediatamente quando o app for
interrompido: use os callbacks de ciclo de vida da atividade
para processar recursos de áudio e vídeo. Se você não estiver usando um app de áudio, pare a reprodução quando
onStop()acontecer nas suas atividades, salve todo o trabalho que estiver realizando e defina seus recursos para serem liberados. Para programar um trabalho que você pode precisar mais tarde. Consulte a seção Tarefas e alarmes.- Você pode usar componentes com reconhecimento do ciclo de vida
como
LiveDataeLifecycleOwnerpara ajudar você a lidar com as chamadas do ciclo de vida da atividade. - Para que seu trabalho reconheça o ciclo de vida, você também pode usar corrotinas do Kotlin e fluxos do Kotlin.
- Você pode usar componentes com reconhecimento do ciclo de vida
como
- Preste atenção na memória do buffer ao buscar vídeos: os desenvolvedores geralmente alocam mais 15 a 60 segundos de conteúdo futuro ao buscar ter vídeos prontos para o usuário, mas isso cria uma sobrecarga de memória adicional.
Em geral, não use mais de 5 segundos de buffer futuro até que o usuário
selecione a nova posição do vídeo. Se você precisar pré-armazenar em buffer
mais tempo durante a busca, faça o seguinte:
- Alocar o buffer de busca com antecedência e reutilizá-lo.
- O tamanho do buffer não pode ser maior que 15 a 25 MB (dependendo da memória do dispositivo).
- Especifique um tamanho variável para os buffers de mídia dependendo da RAM do dispositivo e da resolução de reprodução de vídeo. Isso deve representar 1 minuto
de reprodução de vídeo:
- Alocações:
- Use as orientações sobre memória gráfica para garantir que você não duplique imagens na memória anônima.
- As imagens geralmente são as maiores consumidoras de memória, então a duplicação delas pode pressionar muito o dispositivo. Isso é especialmente verdadeiro durante a navegação intensa em visualizações de grade de imagens.
- Libere as alocações descartando as referências ao mover telas: verifique se não há referências a bitmaps e objetos deixados para trás.
- Use as orientações sobre memória gráfica para garantir que você não duplique imagens na memória anônima.
- Bibliotecas:
- Crie perfis de alocações de memória de bibliotecas ao adicionar novas, já que elas também podem carregar bibliotecas adicionais, o que também pode fazer alocações e criar vinculações.
- Rede:
- Não faça chamadas de rede de bloqueio durante a inicialização do app. Elas diminuem o tempo de inicialização do aplicativo e criam uma sobrecarga de memória adicional no lançamento, quando a memória é particularmente limitada pela carga do app. Mostre uma tela de carregamento ou inicialização primeiro e faça solicitações de rede quando a interface estiver pronta.
Vinculações
Os vínculos introduzem uma sobrecarga de memória adicional porque trazem outros aplicativos para a memória ou aumentam o consumo de memória do app vinculado (se ele já estiver na memória) para facilitar a chamada de API. Isso reduz a memória disponível para o aplicativo em primeiro plano. Ao vincular um serviço, preste atenção em quando e por quanto tempo você está usando a vinculação. Libere a vinculação assim que ela não for mais necessária.
Vinculações típicas e práticas recomendadas:
- API Play Integrity: usada para verificar a integridade do dispositivo.
- Verificar a integridade do dispositivo após a tela de carregamento e antes da reprodução de mídia
- Libere referências ao PlayIntegrity
StandardIntegrityManagerantes de reproduzir o conteúdo.
- Biblioteca Play Faturamento: usada para gerenciar
assinaturas e compras usando o Google Play
- Inicialize a biblioteca depois da tela de carregamento e processe todo o trabalho de faturamento antes de reproduzir qualquer mídia.
- Use
BillingClient.endConnection()ao terminar de usar a biblioteca e sempre antes de reproduzir vídeo ou mídia. - Use
BillingClient.isReady()eBillingClient.getConnectionState()para verificar se o serviço foi desconectado caso seja necessário refazer o trabalho de faturamento. Depois, façaBillingClient.endConnection()de novo.
- GMS FontsProvider
- Prefira usar fontes independentes em dispositivos com pouca RAM em vez de usar um provedor de fontes, já que o download das fontes é caro e o FontsProvider vai vincular serviços para fazer isso.
- Biblioteca do Google Assistente: às vezes usada para pesquisa e pesquisa no app. Se possível, substitua essa biblioteca.
- Para apps leanback: use a biblioteca de conversão de texto em voz do Gboard ou androidx.leanback.
- Siga as diretrizes de pesquisa para implementar a pesquisa.
- Observação: o leanback foi descontinuado, e os apps precisam migrar para o TV Compose.
- Para apps do Compose:
- Use o recurso de conversão de texto em voz do Gboard para implementar a pesquisa por voz.
- Implemente o Assistir a seguir para que o conteúdo de mídia no seu app seja descoberto.
- Para apps leanback: use a biblioteca de conversão de texto em voz do Gboard ou androidx.leanback.
Serviços em primeiro plano
Os serviços em primeiro plano são um tipo especial de serviço vinculado a uma notificação. Essa notificação é mostrada na bandeja de notificações de smartphones e tablets, mas os dispositivos de TV não têm uma bandeja de notificações da mesma forma que esses dispositivos. Mesmo que os serviços em primeiro plano sejam úteis porque podem ser mantidos em execução enquanto o aplicativo está em segundo plano, os apps de TV precisam seguir estas diretrizes:
No Android TV e no Google TV, os serviços em primeiro plano só podem continuar sendo executados depois que o usuário sai do app:
- Para apps de áudio:os serviços em primeiro plano só podem continuar sendo executados depois que o usuário sai do app para continuar tocando a faixa de áudio. O serviço precisa ser interrompido imediatamente após o fim da reprodução de áudio.
- Para qualquer outro app:todos os serviços em primeiro plano precisam ser interrompidos quando o usuário sair do app, já que não há uma notificação para informar que o app ainda está em execução e consumindo recursos.
- Para tarefas em segundo plano, como atualizar recomendações ou
Assistir a seguir, use
WorkManager.
Jobs e alarmes
WorkManager
é a API Android mais moderna para programar jobs recorrentes em segundo plano.
O WorkManager vai usar o novo
JobScheduler quando disponível (SDK
23 ou mais recente) e o antigo AlarmManager quando não estiver. Para práticas recomendadas de execução de jobs programados na TV, siga estas
recomendações:
- Evite usar as APIs
AlarmManagerno SDK 23 ou mais recente, especialmenteAlarmManager.set(),AlarmManager.setExact()e métodos semelhantes, porque eles não permitem que o sistema decida o momento adequado para executar os jobs (por exemplo, quando o dispositivo está ocioso). - Em dispositivos com pouca RAM, evite executar jobs, a menos que seja estritamente necessário. Se necessário, use o WorkManager
WorkRequestapenas para atualizar as recomendações após a reprodução e tente fazer isso enquanto o app ainda estiver aberto. Defina o
Constraintsdo WorkManager para permitir que o sistema execute seus jobs quando for apropriado:
Kotlin
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresStorageNotLow(true)
.setRequiresDeviceIdle(true)
.build()
Java
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresStorageNotLow(true)
.setRequiresDeviceIdle(true)
.build()
- Se você precisar executar jobs regularmente (por exemplo, para atualizar o Assistir a seguir com base na atividade de assistir conteúdo de um usuário no app em outro dispositivo), mantenha o uso de memória baixo, mantendo o consumo de memória do job abaixo de 30 MB.
Considerações gerais sobre a memória
As diretrizes a seguir fornecem informações gerais sobre o desenvolvimento de apps Android:
- Minimize as alocações de objetos, otimize a reutilização de objetos e desalocar objetos não utilizados imediatamente.
- Não mantenha referências a objetos, principalmente bitmaps.
- Evite usar
System.gc()e chamadas diretas de liberação de memória, porque elas interferem no processo de gerenciamento de memória do sistema. Por exemplo, em dispositivos que usam zRAM, uma chamada forçada paragc()pode aumentar temporariamente o uso da memória devido à compressão e descompressão da memória. - Use
LazyList, como demonstrado em um navegador de catálogo no Compose ouRecyclerViewno kit de ferramentas Leanback UI, agora descontinuado, para reutilizar visualizações e não recriar elementos de lista. - Armazene em cache localmente elementos lidos de provedores de conteúdo externos que provavelmente não vão mudar e defina intervalos de atualização que evitem alocar memória externa adicional.
- Verifique se há possíveis vazamentos de memória.
- Cuidado com casos típicos de vazamento de memória, como referências em threads anônimos, realocação de buffers de vídeo que nunca são liberados e outras situações semelhantes.
- Use o heap dump para depurar vazamentos de memória.
- Gere perfis de referência para minimizar a quantidade de compilação just-in-time necessária ao executar o app em uma inicialização a frio.
Noções básicas sobre a recuperação direta de memória
Quando um aplicativo do Android TV solicita memória e o sistema está sob pressão, o kernel do Linux, que sustenta o Android, pode precisar usar a recuperação direta de memória.
O processo envolve pausar completamente qualquer linha de execução de alocação para aguardar páginas de memória liberadas. Isso ocorre quando a recuperação em segundo plano não consegue manter um pool de memória suficiente de forma proativa.
Isso pode levar a pausas ou instabilidade perceptíveis na experiência do usuário, já que o
sistema pausa a alocação de linhas de execução até que memória suficiente seja disponibilizada. Nesse sentido, a alocação de linhas de execução não se limita a chamadas de código de aplicativo, como
malloc(). Por exemplo, a memória precisa ser alocada para a página em páginas de código.
Resumo das ferramentas
- Use a ferramenta Memory Profiler do Android Studio
para verificar o consumo de memória durante o uso.
- Use heapdump para verificar alocações específicas de objetos e bitmaps.
- Use o profiler de memória nativa para verificar alocações que não são Java ou Kotlin.
- Use o Android GPU Inspector para verificar as alocações de gráficos.