Performance do Compose

O objetivo do Jetpack Compose é oferecer uma ótima performance por padrão. Esta página mostra como criar e configurar seu app para melhorar a performance e destaca alguns padrões a serem evitados.

Antes de ler isto, familiarize-se com os principais conceitos do Compose em Como trabalhar com o Compose.

Configurar o app corretamente

Se o app tiver uma performance ruim, isso pode significar que há um problema de configuração. Um bom ponto de partida é verificar as opções de configuração abaixo.

Criar no modo de lançamento e usar o R8

Se você tiver problemas de performance, tente executar o app no modo de lançamento. O modo de depuração é útil para detectar muitos problemas, mas causa um custo de performance significativo e pode dificultar a detecção de outros problemas de código que podem prejudicar a performance. Você também precisa usar o compilador R8 para remover códigos desnecessários do app. Por padrão, a criação no modo de lançamento usa o compilador R8 automaticamente.

Usar um perfil de referência

O Compose é distribuído como uma biblioteca, em vez de fazer parte da plataforma Android. Essa abordagem permite atualizar o Compose com frequência e oferecer suporte a versões mais antigas do Android. No entanto, a distribuição do Compose como uma biblioteca implica em um custo. O código da Plataforma Android já está compilado e instalado no dispositivo. As bibliotecas, por outro lado, precisam ser carregadas quando o app é iniciado e interpretadas just-in-time quando a funcionalidade é necessária. Isso pode deixar o app mais lento na inicialização e sempre que ele usar um recurso da biblioteca pela primeira vez.

É possível melhorar a performance definindo perfis de referência. Esses perfis definem classes e métodos necessários em jornadas ideais do usuário e são distribuídos com o APK do app. Durante a instalação do app, o ART compila esse código essencial com antecedência para que ele esteja pronto para uso quando o app for iniciado.

Nem sempre é fácil definir um bom perfil de referência. Por isso, o Compose oferece um por padrão. Talvez não seja necessário fazer mais nada para aproveitar esse benefício. No entanto, se você definir um perfil próprio, talvez gere um que não melhore a performance do app. Teste o perfil para verificar se ele está ajudando. Uma boa maneira de fazer isso é criando testes Macrobenchmark para o app e verificando os resultados deles à medida que você grava e revisa seu perfil de valor de referência. Confira como criar testes de Macrobenchmark para a IU do Compose em exemplo de Macrobenchmark do Compose (link em inglês).

Para ver uma análise detalhada dos efeitos do modo de lançamento e dos perfis de R8 e referência, consulte a postagem do blog Por que testar a performance do Compose no lançamento? (link em inglês).

Como as três fases do Compose afetam a performance

Conforme discutido em Fases do Jetpack Compose, quando o Compose atualiza um frame, ele passa por três fases:

  • Composição: o Compose determina o que mostrar. Ele executa funções combináveis e cria a árvore de IU.
  • Layout: o Compose determina o tamanho e a posição de cada elemento na árvore da IU.
  • Exibição: o Compose renderiza os elementos da IU individuais.

O Compose pode ignorar essas fases de maneira inteligente se elas não forem necessárias. Por exemplo, suponha que um único elemento gráfico alterne entre dois ícones do mesmo tamanho. Como esse elemento não muda de tamanho e nenhum elemento da árvore da IU é adicionado ou removido, o Compose pode pular as fases de composição e layout e reexibir esse único elemento.

No entanto, alguns erros de programação fazer com que seja difícil para o Compose saber quais fases ele pode ignorar com segurança. Em caso de dúvida, o Compose acaba executando as três fases, o que pode deixar a IU mais lenta do que deveria. Portanto, muitas práticas recomendadas de performance giram em torno de ajudar o Compose a pular as fases desnecessárias.

Há alguns princípios gerais a serem seguidos que podem melhorar a performance em geral.

Em primeiro lugar, sempre que possível, remova os cálculos das funções combináveis. As funções combináveis podem precisar ser executadas novamente sempre que a IU mudar. Qualquer código que você inserir nelas vai ser executado novamente, possivelmente para cada frame de uma animação. Portanto, limite o código do elemento combinável apenas ao que ele precisa para criar a IU.

Em segundo lugar, adie as leituras de estado pelo maior tempo possível. Ao mover a leitura do estado para um elemento combinável filho ou para uma fase posterior, é possível minimizar a recomposição ou pular completamente a fase de composição. Você pode fazer isso transmitindo funções lambda em vez do valor do estado quando ele muda com frequência e priorizando modificadores baseados em lambdas ao transmitir esse estado com mudanças frequentes. Veja um exemplo dessa técnica na seção Adiar leituras pelo maior tempo possível.