Stabilitätsprobleme beheben

Wenn Sie mit einer instabilen Klasse konfrontiert werden, die Leistung verursacht sollte es stabil sein. In diesem Dokument werden mehrere Techniken beschrieben, verwenden können.

Starkes Überspringen aktivieren

Du solltest zuerst versuchen, den starken Überspringenmodus zu aktivieren. Starker Überspringen-Modus ermöglicht das Überspringen von zusammensetzbaren Funktionen mit instabilen Parametern und ist die Methode, um durch Stabilität verursachte Leistungsprobleme zu beheben.

Weitere Informationen finden Sie unter Starkes Überspringen.

Klasse unveränderlich machen

Sie können auch versuchen, eine instabile Klasse vollständig unveränderlich zu machen.

  • Unveränderlich: Gibt einen Typ an, bei dem der Wert eines Attributs niemals sich nach dem Erstellen einer Instanz dieses Typs ändern, und alle Methoden sind referenzieren transparent sind.
    • Achten Sie darauf, dass alle Attribute der Klasse val und nicht var sind. und unveränderlichen Typen.
    • Einfache Typen wie String, Int und Float sind immer unveränderlich.
    • Sollte dies nicht möglich sein, müssen Sie den Erstellungsstatus für alle änderbaren Attribute.
  • Stabil: Gibt einen Typ an, der änderbar ist. Die Compose-Laufzeit werden, ob und wann öffentliche Attribute oder Methoden führt zu anderen Ergebnissen als ein vorheriger Aufruf.

Unveränderliche Sammlungen

Ein häufiger Grund, warum Compose eine Klasse als instabil einstuft, sind Sammlungen. Wie erwähnt auf der Seite Stabilitätsprobleme diagnostizieren den Compiler kann nicht sicher sein, dass Sammlungen wie List, Map und Set sind sie wirklich unveränderlich und werden daher als instabil markiert.

Um dieses Problem zu beheben, können Sie unveränderliche Sammlungen verwenden. Compiler „Compose“ Kotlinx Unmutable Collections wird unterstützt. Diese Sammlungen sind garantiert unveränderlich und werden vom Compose-Compiler behandelt. als solches. Diese Bibliothek befindet sich noch in der Alphaphase, daher sind Änderungen an ihrer API zu erwarten.

Diese instabile Klasse aus der Spalte Stabilität diagnostizieren Leitfaden zu Problemen:

unstable class Snack {
  
  unstable val tags: Set<String>
  
}

Sie können tags mit einer unveränderlichen Sammlung stabil machen. Ändern Sie im Kurs Typ von tags in ImmutableSet<String>:

data class Snack{
    
    val tags: ImmutableSet<String> = persistentSetOf()
    
}

Danach sind alle Parameter der Klasse unveränderlich und der Befehl "Compose" markiert die Klasse als stabil.

Mit Stable oder Immutable annotieren

Sie können Stabilitätsprobleme beheben, indem Sie instabile Klassen mit Anmerkungen versehen. entweder mit @Stable oder @Immutable.

Durch das Annotieren einer Klasse wird das überschrieben, was der Compiler sonst vornehmen würde. Ihre Klasse ableiten. Es ähnelt dem Der Operator !! in Kotlin Sie sollten sehr wie Sie diese Anmerkungen verwenden. Compilerverhalten überschreiben kann es zu unerwarteten Fehlern kommen, z. B. dass Ihre zusammensetzbare Funktion nicht die Sie erwarten.

Wenn es möglich ist, Ihre Klasse ohne Anmerkung stabil zu gestalten, sollten Sie auf diese Weise Stabilität zu erreichen.

Das folgende Snippet zeigt ein minimales Beispiel für eine Datenklasse, die wie folgt annotiert ist: unveränderlich:

@Immutable
data class Snack(

)

Unabhängig davon, ob Sie die Annotation @Immutable oder @Stable verwenden, kennzeichnet die Snack-Klasse als stabil.

Mit Anmerkungen versehene Klassen in Sammlungen

Sehen wir uns eine zusammensetzbare Funktion an, die einen Parameter vom Typ List<Snack> enthält:

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  
  unstable snacks: List<Snack>
  
)

Auch wenn Sie Snack mit @Immutable annotieren, markiert der Compose-Compiler weiterhin snacks-Parameter in HighlightedSnacks als instabil.

Parameter haben bei Sammlungstypen das gleiche Problem wie Klassen. Der Compose-Compiler markiert immer einen Parameter des Typs List als instabil, sogar wenn es sich um eine Sammlung stabiler Typen handelt.

Sie können weder einzelne Parameter als stabil markieren zusammensetzbar sind, damit sie immer überspringbar sind. Es gibt mehrere Wege vorwärts.

Es gibt mehrere Möglichkeiten, das Problem instabiler Sammlungen zu umgehen. In den folgenden Unterabschnitten werden diese Ansätze erläutert.

Konfigurationsdatei

Wenn Sie sich an den Stabilitätsvertrag in Ihrer Codebasis halten, können Sie Kotlin-Sammlungen als stabil erwägen, indem Sie kotlin.collections.* zu deinem Konfigurationsdatei für Stabilität.

Unveränderliche Sammlung

Zur Sicherheit der Unveränderlichkeit für die Kompilierungszeit können Sie Verwenden Sie statt List eine unveränderliche Kotlinx-Sammlung.

@Composable
private fun HighlightedSnacks(
    
    snacks: ImmutableList<Snack>,
    
)

Wrapper

Wenn Sie eine unveränderliche Sammlung nicht verwenden können, können Sie Ihre eigene erstellen. Gehen Sie dazu wie folgt vor: die List in eine annotierte stabile Klasse verpacken. Ein generischer Wrapper ist wahrscheinlich die beste Wahl dafür ist.

@Immutable
data class SnackCollection(
   val snacks: List<Snack>
)

Diesen können Sie dann als Parametertyp in Ihrer zusammensetzbaren Funktion verwenden.

@Composable
private fun HighlightedSnacks(
    index: Int,
    snacks: SnackCollection,
    onSnackClick: (Long) -> Unit,
    modifier: Modifier = Modifier
)

Lösung

Nachdem Sie einen dieser Ansätze gewählt haben, markiert der Compose-Compiler jetzt den HighlightedSnacks Zusammensetzbar als skippable und 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
)

Beim Neuzusammensetzen kann HighlightedSnacks jetzt übersprungen werden, wenn keine Eingaben geändert.

Konfigurationsdatei für die Stabilität

Beginnend mit Compose Compiler 1.5.5, einer Konfigurationsdatei mit Klassen, stabil kann bei der Kompilierung bereitgestellt werden. So können Sie sich überlegen, Klassen, die Sie nicht steuern, z. B. Standardbibliotheksklassen wie LocalDateTime als stabil.

Die Konfigurationsdatei ist eine Nur-Text-Datei mit einer Klasse pro Zeile. Kommentare, einfache und doppelte Platzhalter unterstützt werden. Im Folgenden finden Sie eine Beispielkonfiguration:

// 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<*,_>

Um diese Funktion zu aktivieren, übergeben Sie den Pfad der Konfigurationsdatei an das Compiler-Optionen.

Cool

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"
  )
}

Da der Compose-Compiler für jedes Modul in Ihrem Projekt separat ausgeführt wird, können Sie bei Bedarf unterschiedliche Konfigurationen für verschiedene Module bereitstellen. Alternativ haben Sie die Möglichkeit, die Konfiguration auf der Stammebene Ihres Projekts aus und übergeben Sie diesen Pfad an jede -Modul.

Mehrere Module

Ein weiteres häufiges Problem betrifft die Architektur mit mehreren Modulen. Compiler „Compose“ kann nur ableiten, ob eine Klasse stabil ist, wenn alle nicht-primitiven Typen, die Referenzen sind entweder explizit als stabil gekennzeichnet oder in einem Modul, auch mit dem Compose-Compiler erstellt.

Befindet sich die Datenschicht in einem anderen Modul als der UI-Ebene, empfohlenen Lösungsansatz, könnte es ein Problem sein, das bei Ihnen auftritt.

Lösung

Dieses Problem lässt sich mit einer der folgenden Methoden beheben:

  1. Fügen Sie die Klassen der Compiler-Konfigurationsdatei hinzu.
  2. Aktivieren Sie den Compiler Compose in Ihren Datenschichtmodulen oder taggen Sie Ihre Klassen gegebenenfalls mit @Stable oder @Immutable.
    • Dazu muss der Datenschicht eine Schreibabhängigkeit hinzugefügt werden. Sie können jedoch Es handelt sich nur um die Abhängigkeit für die Compose-Laufzeit, nicht für Compose-UI
  3. Binden Sie die Datenschichtklassen im UI-Modul in einen UI-spezifischen Wrapper ein. Klassen.

Das gleiche Problem tritt auch auf, wenn externe Bibliotheken verwendet werden, wenn diese nicht die Compiler erstellen.

Nicht jede zusammensetzbare Funktion sollte überspringbar sein.

Wenn Sie Stabilitätsprobleme beheben, sollten Sie nicht versuchen, zusammensetzbar, überspringbar. Ein solcher Versuch kann zu einer vorzeitigen Optimierung führen bringt mehr Probleme mit sich, als sie behoben werden.

Es gibt viele Situationen, in denen überspringbare Anzeigen keine nennenswerten Vorteile haben. und den Code zu verwalten. Beispiel:

  • Eine zusammensetzbare Funktion, die nicht oft oder überhaupt neu zusammengesetzt wird.
  • Eine zusammensetzbare Funktion, die allein als „überspringbare zusammensetzbare Funktionen“ bezeichnet wird.
  • Zusammensetzbare Funktion mit einer großen Anzahl von Parametern und teuren Gleichheitszeichen Implementierungen. In diesem Fall werden die Kosten für die Prüfung, ob einer der Parameter die Kosten einer billigen Neuzusammensetzung überwiegen können.

Wenn eine zusammensetzbare Funktion überspringbar ist, entsteht ein geringer Mehraufwand, der sich vielleicht nicht lohnen würde. . Sie haben sogar die Möglichkeit, die zusammensetzbare Funktion so zu kennzeichnen, dass sie in Fällen nicht wieder gestartet werden kann. dass ein Neustart mehr Aufwand verursacht, als er wert ist.