w przypadku niestabilnej klasy, która powoduje wydajność; problemów, zadbaj o to, by była stabilna. W tym dokumencie opisujemy kilka metod, które można wykorzystać.
Włącz silne pomijanie
Najpierw spróbuj włączyć silny tryb pomijania. Silny tryb pomijania umożliwia pomijanie elementów kompozycyjnych z niestabilnymi parametrami. Jest to najłatwiejszy rozwiązania problemów z wydajnością spowodowanych przez stabilność.
Więcej informacji znajdziesz w sekcji Silne pomijanie.
Ustaw klasę jako niezmienną
Możesz też spróbować uczynić klasę niestabilną całkowicie.
- Stała: wskazuje typ, w przypadku którego wartość dowolnej właściwości nigdy nie może zostać
zmiany po utworzeniu wystąpienia tego typu, a wszystkie metody
w sposób niezależny od kontekstu.
- Upewnij się, że wszystkie właściwości klasy to
val
, a nievar
, typów stałych. - Typy podstawowe, takie jak
String, Int
iFloat
, są zawsze stałe. - Jeśli to niemożliwe, użyj stanu tworzenia dla jakichkolwiek zmiennych.
- Upewnij się, że wszystkie właściwości klasy to
- Stabilny: oznacza typ, który jest zmienny. Środowisko wykonawcze Compose nie dowiedzieć się, czy i kiedy jakiekolwiek publiczne właściwości lub metody tego typu da inne rezultaty w porównaniu z poprzednim wywołaniem.
Kolekcje stałe
Częstym powodem, dla którego funkcja Compose jest uważana za niestabilną klasę, są kolekcje. Jak zaznaczono
na stronie Diagnozuj problemy ze stabilnością, kompilator Compose
nie można dokładnie określić, czy kolekcje, takie jak List, Map
i Set
, są
są naprawdę trwałe i dlatego oznaczają je jako niestabilne.
Aby rozwiązać ten problem, możesz użyć kolekcji stałych. Kompilator Compose obejmuje obsługę kolekcji stałych Kotlinx. Te kolekcji są stałe, a kompilator Compose traktuje je w taki sposób. Ta biblioteka jest nadal w wersji alfa, możesz się więc spodziewać zmian w interfejsie API.
Ponownie rozważ zastosowanie tej niestabilnej klasy przedstawionej w sekcji Zdiagnozuj stabilność :
unstable class Snack {
…
unstable val tags: Set<String>
…
}
Możesz utworzyć stabilną wersję tags
za pomocą kolekcji stałej. Na stronie zajęć zmień
typ od tags
do ImmutableSet<String>
:
data class Snack{
…
val tags: ImmutableSet<String> = persistentSetOf()
…
}
Po wykonaniu tej czynności wszystkie parametry klasy pozostają niezmienne, a funkcja Compose kompilator oznacza klasę jako stabilną.
Dodaj adnotację w formacie Stable
lub Immutable
Możliwym sposobem rozwiązania problemów ze stabilnością jest dodanie adnotacji do klas niestabilnych
z parametrem @Stable
lub @Immutable
.
Dodawanie adnotacji do klasy zastępuje to, co w innym przypadku kompilator
wywnioskować na temat swoich zajęć. Jest to podobne do
!!
w Kotlin. Należy być bardzo
z ostrożnością, jak ich używasz. Zastępowanie działania kompilatora
może to prowadzić do nieprzewidzianych błędów,
np. gdy funkcja kompozycyjna nie uruchamia się ponownie,
których oczekujesz.
Jeśli można uczynić klasę stabilną bez adnotacji, wykonaj i dążenie do osiągnięcia stabilności w ten sposób.
Ten fragment kodu zawiera minimalny przykład klasy danych z adnotacjami jako stały:
@Immutable
data class Snack(
…
)
Niezależnie od tego, czy używasz adnotacji @Immutable
czy @Stable
, kompilator Compose
oznacza klasę Snack
jako stabilną.
Zajęcia z adnotacjami w kolekcjach
Rozważ funkcję kompozycyjną zawierającą parametr typu List<Snack>
:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
…
unstable snacks: List<Snack>
…
)
Nawet jeśli dodasz adnotacje do Snack
za pomocą @Immutable
, kompilator Compose nadal będzie oznaczać znaczniki
parametr snacks
w funkcji HighlightedSnacks
jako niestabilny.
Parametry mają taki sam problem jak klasy, jeśli chodzi o typy kolekcji.
Kompilator Compose zawsze oznacza parametr typu List
jako niestabilny, nawet
gdy jest to zbiór typów stałych.
Nie można oznaczyć pojedynczego parametru jako stabilnego ani dodać adnotacji ale kompozycyjne, by zawsze można je było pominąć. Istnieje wiele ścieżek do przodu.
Problem z niestabilnymi kolekcjami można rozwiązać na kilka sposobów. W poniższych sekcjach opisaliśmy różne podejścia.
Plik konfiguracji
Jeśli chcesz przestrzegać umowy dotyczącej stabilności w bazie kodu,
możesz zdecydować się na uznanie kolekcji Kotlin jako stabilne, dodając
kotlin.collections.*
na
plik konfiguracji stabilności.
Kolekcja stała
Aby skompilować bezpieczeństwo czasu związane z niezmiennością, możesz
używa stałej kolekcji kotlinx zamiast List
.
@Composable
private fun HighlightedSnacks(
…
snacks: ImmutableList<Snack>,
…
)
Wrapper
Jeśli nie możesz użyć kolekcji stałej, możesz utworzyć własną. Aby to zrobić:
umieść List
w klasie stabilnej z adnotacjami. Ogólny kod jest prawdopodobnie
w zależności od wymagań.
@Immutable
data class SnackCollection(
val snacks: List<Snack>
)
Następnie możesz użyć go jako typu parametru w elemencie kompozycyjnym.
@Composable
private fun HighlightedSnacks(
index: Int,
snacks: SnackCollection,
onSnackClick: (Long) -> Unit,
modifier: Modifier = Modifier
)
Rozwiązanie
Po zastosowaniu dowolnej z tych metod kompilator Compose oznacza teraz
HighlightedSnacks
Możliwość tworzenia zarówno jako skippable
, jak i restartable
.
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
stable snacks: ImmutableList<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)
Podczas ponownego komponowania funkcji Utwórz może teraz pominąć HighlightedSnacks
, jeśli nie ma
dane wejściowe uległy zmianie.
Plik konfiguracji stabilności
Począwszy od Compose Compiler 1.5.5, pliku konfiguracji klas do
powinny być stabilne i można je udostępnić podczas kompilacji. Dzięki temu
klasy, których nie kontrolujesz, takie jak standardowe klasy biblioteki
na przykład LocalDateTime
, jako stabilną.
Plik konfiguracji jest zwykłym plikiem tekstowym z jedną klasą na wiersz. Komentarze jedno i podwójne symbole wieloznaczne. Oto przykładowa konfiguracja:
// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider kotlin collections stable
kotlin.collections.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>
Aby włączyć tę funkcję, przekaż ścieżkę pliku konfiguracji do narzędzia Compose kompilatora.
Odlotowe
kotlinOptions {
freeCompilerArgs += [
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
project.absolutePath + "/compose_compiler_config.conf"
]
}
Kotlin
kotlinOptions {
freeCompilerArgs += listOf(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:stabilityConfigurationPath=" +
"${project.absolutePath}/compose_compiler_config.conf"
)
}
Ponieważ kompilator Compose działa w każdym module w projekcie oddzielnie, możesz w razie potrzeby możesz skonfigurować różne konfiguracje różnym modułom. Możesz też utworzyć na poziomie głównym projektu i przekazać tę ścieżkę do każdego .
Wiele modułów
Innym częstym problemem jest architektura wielomodułowa. Kompilator Compose może wywnioskować, czy klasa jest stabilna, jeśli wszystkie typy inne niż podstawowe, są wyraźnie oznaczone jako stabilne lub w module, także za pomocą kompilatora Compose.
Jeśli warstwa danych znajduje się w osobnym module warstwy interfejsu, który jest zalecane podejście, może to być problem, który napotykasz.
Rozwiązanie
Aby rozwiązać ten problem, możesz zastosować jedną z tych metod:
- Dodaj klasy do pliku konfiguracji kompilatora.
- Włącz kompilator Compose w modułach warstwy danych lub otaguj zajęcia
w razie potrzeby poleceniem
@Stable
lub@Immutable
.- Wymaga to dodania zależności tworzenia wiadomości do warstwy danych. Pamiętaj jednak:
dotyczy jedynie środowiska wykonawczego Compose, a nie środowiska wykonawczego
Compose-UI
- Wymaga to dodania zależności tworzenia wiadomości do warstwy danych. Pamiętaj jednak:
dotyczy jedynie środowiska wykonawczego Compose, a nie środowiska wykonawczego
- W module interfejsu opakuj klasy warstwy danych w kod towarzyszący UI zajęcia.
Ten sam problem występuje też przy korzystaniu z bibliotek zewnętrznych, jeśli nie korzystają z biblioteki Kompilator tworzenia wiadomości.
Nie wszystkie elementy kompozycyjne muszą być możliwe do pominięcia
Podczas rozwiązywania problemów ze stabilnością, ale też kompozycyjne, które można pominąć. Próba wykonania tej czynności może doprowadzić do przedwczesnej optymalizacji który wprowadza więcej błędów niż naprawia.
Jest wiele sytuacji, w których możliwość pominięcia nie przynosi żadnych realnych korzyści. i może utrudniać utrzymanie kodu. Na przykład:
- Element kompozycyjny, który nie podlega ponownej kompozycji lub w ogóle nie jest skomponowany.
- Elementy kompozycyjne, które same w sobie nazywane są elementami kompozycyjnymi możliwymi do pominięcia.
- Element kompozycyjny z dużą liczbą parametrów z drogimi parametrami równa się implementacji. W tym przypadku koszt sprawdzenia, czy którykolwiek parametr ma może przeważyć koszt taniej zmiany kompozycji.
Gdy element kompozycyjny jest możliwy do pominięcia, wiąże się to z niewielkim narzutem, który może nie być wart . Możesz nawet dodać adnotację do kompozycji, by nie dało się jej ponownie uruchomić, w którym stwierdzasz, że możliwość ponownego uruchomienia jest większa niż warta.