Modo forte para pular

O modo de rejeição avançada está disponível no compilador do Compose. Quando ativado, ele muda o comportamento do compilador de duas maneiras:

  • Os elementos combináveis com parâmetros instáveis podem ser pulados.
  • As lambdas com capturas instáveis são gravadas

Ativar o modo de rejeição avançada

Para ativar o salto forte para um módulo do Gradle em uma versão anterior, inclua a seguinte opção no bloco composeCompiler da configuração do Gradle:

android { ... }

composeCompiler {
   enableStrongSkippingMode = true
}

Recurso combinável para pular

O modo de pular forte relaxa algumas das regras de estabilidade normalmente aplicadas pelo compilador do Compose quando se trata de pular e de funções combináveis. Por padrão, o compilador do Compose marcará uma função combinável como pulável se todos os argumentos tiverem valores estáveis. O modo de rejeição avançada muda isso.

Com a omissão forte ativada, todas as funções combináveis reiniciáveis se tornam omitíveis. Isso acontece com parâmetros instáveis ou não. As funções combináveis não reiniciáveis não podem ser puladas.

Quando pular

Para determinar se um elemento combinável será ignorado durante a recomposição, o Compose compara o valor de cada parâmetro com os valores anteriores. O tipo de comparação depende da estabilidade do parâmetro.

  • Os parâmetros instáveis são comparados usando a igualdade de instância (===)
  • Os parâmetros estáveis são comparados usando a igualdade de objetos (Object.equals()).

Se todos os parâmetros atenderem a esses requisitos, o Compose vai pular o elemento combinável durante a recomposição.

Você pode querer que um elemento combinável desative a opção "Pular forte". Ou seja, talvez você queira um elemento combinável reinicializável, mas não pulável. Nesse caso, use a anotação @NonSkippableComposable.

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

Anotar classes como estáveis

Se você quiser que um objeto use a igualdade de objeto em vez da igualdade de instância, continue a anotar a classe especificada com @Stable. Um exemplo de quando você pode precisar fazer isso é ao observar uma lista inteira de objetos. As fontes de dados, como o Room, vão alocar novos objetos para cada item da lista sempre que um deles mudar.

Memorização Lambda

O modo de pular forte também permite mais memoização de lambdas dentro dos elementos combináveis. Com a rejeição avançada ativada, cada lambda dentro de uma função combinável é lembrada automaticamente.

Exemplos

Para conseguir a memorização de lambdas dentro de elementos combináveis ao usar a ação de pular forte, o compilador envolve a lambda com uma chamada remember. Ela é codificada com as capturas da lambda.

Considere um caso em que você tem uma lambda como no exemplo abaixo:

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = {
        use(unstableObject)
        use(stableObject)
    }
}

Com o salto forte ativado, o compilador memoriza a lambda ao envolvê-la em uma chamada remember:

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = remember(unstableObject, stableObject) {
        {
            use(unstableObject)
            use(stableObject)
        }
    }
}

As chaves seguem as mesmas regras de comparação que as funções combináveis. O ambiente de execução compara chaves instáveis usando a igualdade de instâncias. Ela compara chaves estáveis usando a igualdade de objetos.

Memoização e recomposição

Essa otimização aumenta muito o número de elementos combináveis que o ambiente de execução ignora durante a recomposição. Sem a memorização, é muito mais provável que o ambiente de execução aloque uma nova lambda para qualquer elemento combinável que receba um parâmetro lambda durante a recomposição. Como resultado, a nova lambda tem parâmetros que não são iguais à última composição. Isso resulta na recomposição.

Evitar a memorização

Se você tiver uma lambda que não quer armazenar em cache, use a anotação @DontMemoize.

val lambda = @DontMemoize {
    ...
}

Tamanho do APK

Quando compilados, os elementos combináveis que podem ser pulados resultam em mais código gerado do que elementos combináveis que não podem ser pulados. Com o salto forte ativado, o compilador marca quase todos os elementos combináveis como saltáveis e envolve todos os lambdas em um remember{...}. Por isso, ativar o modo de rejeição avançada tem um impacto muito pequeno no tamanho do APK do seu aplicativo.

A ativação de pulos fortes no Now in Android (link em inglês) aumentou o tamanho do APK em 4 KB. A diferença no tamanho depende em grande parte do número de elementos combináveis não ignoráveis que estavam presentes no app, mas deve ser relativamente pequena.