Silne pomijanie to tryb dostępny w kompilatorze Compose. Gdy ta opcja jest włączona, zmienia działanie kompilatora na 2 sposoby:
- Komponenty z niestabilnymi parametrami stają się możliwe do pominięcia.
- Lambdy z niestabilnymi przechwyceniami są zapamiętywane
Włącz tryb silnego pomijania
W Kotlinie 2.0.20 silne pomijanie jest domyślnie włączone.
Aby włączyć silne pomijanie w module Gradle w wersji starszej niż 2.0.20, dodaj tę opcję w bloku composeCompiler konfiguracji Gradle:
android { ... }
composeCompiler {
enableStrongSkippingMode = true
}
Możliwość pominięcia w przypadku funkcji kompozycyjnych
Tryb silnego pomijania rozluźnia niektóre reguły stabilności, które kompilator Compose zwykle stosuje w przypadku pomijania i funkcji typu „composable”. Domyślnie kompilator Compose oznacza funkcję typu „composable” jako możliwą do pominięcia, jeśli wszystkie jej argumenty mają stabilne wartości. Tryb silnego pomijania to zmienia.
Gdy włączone jest silne pomijanie, wszystkie funkcje typu „composable”, które można uruchomić ponownie, można też pominąć. Dotyczy to zarówno parametrów niestabilnych, jak i stabilnych. Funkcje typu „composable”, których nie można uruchomić ponownie, pozostają niepomijalne.
Kiedy pominąć
Aby określić, czy pominąć funkcję kompozycyjną podczas rekompozycji, Compose porównuje wartość każdego parametru z jego poprzednimi wartościami. Typ porównania zależy od stabilności parametru.
- Niestabilne parametry są porównywane za pomocą równości instancji (
===) - Stabilne parametry są porównywane za pomocą równości obiektów (
Object.equals())
Jeśli wszystkie parametry spełniają te wymagania, Compose pomija funkcję kompozycyjną podczas rekompozycji.
Możesz chcieć, aby funkcja kompozycyjna nie korzystała z silnego pomijania. Oznacza to, że możesz chcieć, aby funkcja kompozycyjna była możliwa do ponownego uruchomienia, ale niemożliwa do pominięcia. W takim przypadku użyj adnotacji @NonSkippableComposable.
@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}
Oznaczanie klas jako stabilnych
Jeśli chcesz, aby obiekt był porównywany przy użyciu równości obiektów (Object.equals()) zamiast równości instancji (===), nadal dodawaj do danej klasy adnotację @Stable lub @Immutable.
Zanim dodasz @Stable lub @Immutable, weź pod uwagę te kompromisy:
- Klasy ze stabilnymi właściwościami w modułach Compose są już stabilne: klasa z właściwościami
valo stabilnych typach w module skompilowanym za pomocą kompilatora Compose jest automatycznie uznawana za stabilną i używa.equals()bez konieczności stosowania@Immutablelub@Stable. - Dodawaj adnotacje tylko do klas z prostymi kontrolami
.equals(): dodaj@Stablelub@Immutable, gdy kompilator nie może wywnioskować stabilności (np. w przypadku klas z modułów innych niż Compose) i często są przydzielane nowe instancje o identycznych wartościach, pod warunkiem że kontrola.equals()klasy jest prosta. - Zachowaj ostrożność podczas dodawania adnotacji do modeli z kolekcjami: dodanie adnotacji
@Stablelub@Immutabledo modeli zawierających kolekcje (lub zastąpienie adnotacjiListadnotacjąImmutableList) powoduje, że Compose porównuje każdy element w kolekcji z adnotacją.equals()przy każdym przebiegu rekompozycji. W przypadku dużych kolekcji lub modeli używanych w układach leniwych (LazyColumn,LazyRow,LazyGrid) porównywanie każdego elementu może być wolniejsze niż użycie równości instancji (===) lub bezpośrednia rekompozycja.
Zapamiętywanie funkcji lambda
Tryb silnego pomijania umożliwia też większą memoizację funkcji lambda w funkcjach kompozycyjnych. Po włączeniu silnego pomijania każda funkcja lambda w funkcji typu „composable” będzie automatycznie zapamiętywana.
Przykłady
Aby uzyskać zapamiętywanie funkcji lambda w funkcjach kompozycyjnych podczas korzystania z silnego pomijania, kompilator opakowuje funkcję lambda wywołaniem remember. Jest on powiązany z przechwytywaniem wyrażenia lambda.
Rozważmy przypadek, w którym masz funkcję lambda, jak w tym przykładzie:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = {
use(unstableObject)
use(stableObject)
}
}
Gdy włączone jest silne pomijanie, kompilator zapamiętuje funkcję lambda, opakowując ją w wywołanie remember:
@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
val lambda = remember(unstableObject, stableObject) {
{
use(unstableObject)
use(stableObject)
}
}
}
Klucze podlegają tym samym regułom porównywania co funkcje typu „composable”. Środowisko wykonawcze porównuje niestabilne klucze, używając równości instancji. Porównuje stabilne klucze, używając równości obiektów.
Zapamiętywanie i rekompozycja
Ta optymalizacja znacznie zwiększa liczbę funkcji kompozycyjnych, które środowisko wykonawcze pomija podczas rekompozycji. Bez zapamiętywania środowisko wykonawcze znacznie częściej przydziela nową funkcję lambda do dowolnego elementu kompozycyjnego, który przyjmuje parametr lambda podczas rekompozycji. W rezultacie nowa funkcja lambda ma parametry, które nie są równe ostatniej kompozycji. Powoduje to rekompozycję.
Unikaj zapamiętywania
Jeśli masz funkcję lambda, której nie chcesz zapamiętywać, użyj adnotacji @DontMemoize.
val lambda = @DontMemoize {
...
}
Rozmiar pliku APK
Po skompilowaniu elementy kompozycyjne, które można pominąć, generują więcej kodu niż te, których nie można pominąć. Gdy włączone jest silne pomijanie, kompilator oznacza prawie wszystkie funkcje kompozycyjne jako możliwe do pominięcia i opakowuje wszystkie lambdy w remember{...}. Z tego powodu włączenie trybu silnego pomijania ma bardzo mały wpływ na rozmiar pliku APK aplikacji.
Włączenie silnego pomijania w aplikacji Now In Android zwiększyło rozmiar pliku APK o 4 kB. Różnica w rozmiarze zależy głównie od liczby wcześniej niepomijalnych elementów kompozycyjnych, które były obecne w danej aplikacji, ale powinna być stosunkowo niewielka.