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:

  • 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

A omissão forte é ativada por padrão no Kotlin 2.0.20.

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

android { ... }

composeCompiler {
   enableStrongSkippingMode = true
}

Recurso pulável combinável

O modo de pular forte relaxa algumas das regras de estabilidade normalmente aplicadas pelo compilador do Compose quando se trata de pular e funções combináveis. Por padrão, o compilador do Compose marca uma função combinável como pular 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 vale mesmo que eles tenham parâmetros instáveis. As funções combináveis não reiniciáveis continuam sem poder 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 combinável durante a recomposição.

Talvez você queira que um elemento combinável desative a omissão forte. Ou seja, você pode querer um elemento combinável reiniciável, mas não pulado. Nesse caso, use a anotação @NonSkippableComposable.

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

Anotar classes como estáveis

Se você quiser um objeto usando igualdade de objeto em vez de 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 rejeição avançada também permite mais memorização de lambdas dentro de elementos combináveis. Com a rejeição avançada ativada, cada lambda dentro de uma função combinável é lembrada automaticamente.

Exemplos

Para alcançar a memorização de lambdas dentro de elementos combináveis ao usar o salto forte, o compilador envolve a lambda com uma chamada remember. Ele é codificado com as capturas da lambda.

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

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

Com a rejeição avançada ativada, o compilador armazena em cache a lambda, envolvendo-a 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 das funções combináveis. O ambiente de execução compara chaves instáveis usando a igualdade de instâncias. Ele 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 pula 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.

Evite 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 pulá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.

Ativar o salto forte no Now In Android 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.