Estabilidade no Compose

O Compose considera os tipos como estáveis ou instáveis. Um tipo é estável se é imutável, ou se é possível para o Compose saber se o valor tem mudou entre as recomposições. Um tipo é instável quando o Compose não consegue saber se seu valor mudou entre as recomposições.

O Compose usa a estabilidade dos parâmetros de um elemento combinável para determinar se ele pode pular o elemento combinável durante a recomposição:

  • Parâmetros estáveis:se um elemento combinável tem parâmetros estáveis que não foram for alterado, o Compose a ignorará.
  • Parâmetros instáveis:se um elemento combinável tiver parâmetros instáveis, o Compose sempre o recompõe ao recompor o pai do componente.

Se o app inclui muitos componentes desnecessariamente instáveis que o Compose sempre usa durante a recomposição, poderá observar problemas de desempenho e outros problemas.

Este documento detalha como aumentar a estabilidade do seu app para melhorar desempenho e experiência geral do usuário.

Objetos imutáveis

Os snippets a seguir demonstram os princípios gerais por trás da estabilidade e recomposição.

A classe Contact é de dados imutável. Isso porque todos os seus parâmetros são primitivos definidos com a palavra-chave val. Depois de criar um instância de Contact, não será possível alterar o valor das propriedades do objeto. Se você tentasse fazer isso, criaria um novo objeto.

data class Contact(val name: String, val number: String)

O elemento combinável ContactRow tem um parâmetro do tipo Contact.

@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
   var selected by remember { mutableStateOf(false) }

   Row(modifier) {
      ContactDetails(contact)
      ToggleButton(selected, onToggled = { selected = !selected })
   }
}

Considere o que acontece quando o usuário clica no botão ativar e o selected mudança de estado:

  1. O Compose avalia se precisa recompor o código dentro de ContactRow.
  2. Ele percebe que o único argumento para ContactDetails é do tipo Contact.
  3. Como Contact é uma classe de dados imutável, o Compose garante que nenhuma os argumentos de ContactDetails mudaram.
  4. Dessa forma, o Compose ignora a ContactDetails e não a recompõe.
  5. Por outro lado, os argumentos de ToggleButton mudaram. O Compose faz a recomposição desse componente.

Objetos mutáveis

Embora o exemplo anterior use um objeto imutável, é possível criar um um objeto mutável. Confira o snippet a seguir:

data class Contact(var name: String, var number: String)

Como cada parâmetro de Contact agora é um var, a classe não é mais imutável. Se as propriedades fossem alteradas, o Compose não ficaria ciente disso. Isso ocorre porque O Compose só monitora mudanças em objetos de estado do Compose.

O Compose considera essa classe instável. O Compose não ignora a recomposição de classes instáveis. Dessa forma, se Contact for definido dessa maneira, ContactRow no exemplo anterior, seria recomposta sempre que selected mudasse.

Implementação no Compose

Pode ser útil, embora não seja crucial, considerar exatamente como o Compose determina quais funções pular durante a recomposição.

Quando o compilador do Compose é executado no seu código, ele marca cada função e tipo. com uma das várias tags. Essas tags refletem como o Compose processa a função ou durante a recomposição.

Funções

O Compose pode marcar funções como skippable ou restartable. Observe que pode marcar uma função como um, ambos ou nenhum destes:

  • Pulável: se o compilador marcar um elemento combinável como pulável, o Compose poderá ignorá-la durante a recomposição se todos os seus argumentos forem iguais à própria valores anteriores.
  • Reinicializável: um elemento combinável que pode ser reiniciado serve como um "escopo". em que a recomposição pode começar. Em outras palavras, a função pode ser um ponto de entrada de onde o Compose pode começar a executar novamente o código para recomposição após as mudanças de estado.

Tipos

O Compose marca os tipos como imutáveis ou estáveis. Cada tipo é um ou o outro:

  • Imutável: o Compose marca um tipo como imutável se o valor dele propriedades nunca podem mudar e todos os métodos são referenciais transparentes.
    • Todos os tipos primitivos são marcados como imutáveis. Isso inclui String, Int e Float.
  • Estável: indica um tipo com propriedades que podem ser alteradas após a construção. Se e quando essas propriedades mudarem durante o tempo de execução, o Compose vai reconhecer essas mudanças.
.

Depurar estabilidade

Se o app estiver recompondo um elemento combinável que não teve parâmetros alterados, primeiro verifique a definição de parâmetros que são claramente mutáveis. Escrever sempre recompõe um componente quando você transmite um tipo com as propriedades var ou um val que usam um tipo instável conhecido.

Para informações detalhadas sobre como diagnosticar problemas complexos com estabilidade em Compose, consulte o guia Depurar estabilidade.

Corrigir problemas de estabilidade

Para saber mais sobre como oferecer estabilidade na implementação do Compose, consulte o guia Corrigir problemas de estabilidade.

Resumo

Em geral, você deve observar os seguintes pontos:

  • Parâmetros: o Compose determina a estabilidade de cada parâmetro do elementos combináveis para determinar quais elementos devem ser ignorados durante recomposição.
  • Correções imediatas: se você notar que o elemento combinável não está sendo ignorado e ela está causando um problema de desempenho, verifique as causas óbvias instabilidade como parâmetros var primeiro.
  • Relatórios do compilador: você pode usar os relatórios do compilador para determinar a estabilidade das classes.
  • Coleções: o Compose sempre considera as classes de coleção instáveis, como como List, Set e Map. Isso ocorre porque não é possível garantir que eles são imutáveis. Use as coleções imutáveis do Kotlinx ou anotar suas classes como @Immutable ou @Stable;
  • Outros módulos: o Compose sempre considera instável a origem deles. módulos em que o compilador do Compose não é executado. Unir as classes na interface classes de modelo, se necessário.

Leia mais