Diagnozowanie problemów ze stabilnością

Jeśli masz problemy z wydajnością, które wynikają z niepotrzebnych lub nadmiernej zmiany układu aplikacji, debuguj jej stabilność. W tym przewodniku omawiamy kilka sposobów, które pomogą Ci to zrobić.

Inspektor układu

Za pomocą Inspektora układu w Android Studio możesz sprawdzić, które funkcje kompozycyjne są rekomponowane w Twojej aplikacji. Pokazuje on, ile razy funkcja Tworzenie ponownie skomponowała lub pominęła dany komponent.

Liczniki zmian kompozycji i pominięcia w Inspektorze układu

Tworzenie raportów kompilatora

Kompilator Compose może wyświetlić wyniki swojego wnioskowania dotyczącego stabilności na potrzeby kontroli. Na podstawie tych danych wyjściowych możesz określić, które elementy kompozycyjne można pominąć, a które nie. Poniżej opisujemy, jak korzystać z tych raportów. Szczegółowe informacje znajdziesz w dokumentacji technicznej.

Skonfiguruj

Raporty kompilatora kompilatora nie są domyślnie włączone. Można je aktywować za pomocą flagi kompilatora. Dokładna konfiguracja zależy od projektu, ale w większości projektów możesz wkleić ten skrypt do pliku głównego build.gradle.

Odlotowy

subprojects {
  tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
        kotlinOptions {
            if (project.findProperty("composeCompilerReports") == "true") {
                freeCompilerArgs += [
                        "-P",
                        "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" +
                                project.buildDir.absolutePath + "/compose_compiler"
                ]
            }
            if (project.findProperty("composeCompilerMetrics") == "true") {
                freeCompilerArgs += [
                        "-P",
                        "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" +
                                project.buildDir.absolutePath + "/compose_compiler"
                ]
            }
        }
    }
}

Kotlin

subprojects {
    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
        kotlinOptions {
            if (project.findProperty("composeCompilerReports") == "true") {
                freeCompilerArgs += listOf(
                    "-P",
                    "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_compiler"
                )
            }
            if (project.findProperty("composeCompilerMetrics") == "true") {
                freeCompilerArgs += listOf(
                    "-P",
                    "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_compiler"
                )
            }
        }
    }
}

Uruchamianie zadania

Aby debugować stabilność elementów kompozycyjnych, uruchom to zadanie:

./gradlew assembleRelease -PcomposeCompilerReports=true

Przykładowe dane wyjściowe

To zadanie generuje 3 pliki. Oto przykładowe dane wyjściowe z usługi JetSnack.

  • <modulename>-classes.txt: raport o stabilności klas w tym module. Przykład.
  • <modulename>-composables.txt: raport o tym, jak ponownie dostępne i pomijalne są w module kompozycje. Przykład.
  • <modulename>-composables.csv: wersja w formacie CSV raportu o elementach kompozycyjnych, którą można zaimportować do arkusza kalkulacyjnego lub przetworzyć za pomocą skryptu. Próbka

Raport dotyczący elementów kompozycyjnych

Plik composables.txt zawiera szczegółowe informacje o poszczególnych funkcjach kompozycyjnych danego modułu, w tym o stabilności ich parametrów oraz o tym, czy można je ponownie uruchomić czy pominąć. Oto hipotetyczny przykład usługi JetSnack:

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
  stable snackCollection: SnackCollection
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
  stable index: Int = @static 0
  stable highlight: Boolean = @static true
)

Ten element kompozycyjny SnackCollection jest w pełni możliwy do ponownego uruchomienia, możliwy do pominięcia i stabilny. Zwykle jest to korzystne, ale nie jest obowiązkowe.

Z drugiej strony posłużmy się innym przykładem.

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  unstable snacks: List<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

Elementu kompozycyjnego HighlightedSnacks nie można pominąć. Funkcja tworzenia wiadomości nie pomija jej podczas zmiany kompozycji. Dzieje się tak nawet wtedy, gdy żaden z parametrów nie uległ zmianie. Przyczyną jest parametr unstable (snacks).

Raport dotyczący zajęć

Plik classes.txt zawiera podobny raport na temat klas w danym module. Ten fragment kodu jest wynikiem działania klasy Snack:

unstable class Snack {
  stable val id: Long
  stable val name: String
  stable val imageUrl: String
  stable val price: Long
  stable val tagline: String
  unstable val tags: Set<String>
  <runtime stability> = Unstable
}

Oto definicja słowa Snack w celach informacyjnych:

data class Snack(
    val id: Long,
    val name: String,
    val imageUrl: String,
    val price: Long,
    val tagline: String = "",
    val tags: Set<String> = emptySet()
)

Kompilator Compose oznaczył wersję Snack jako niestabilną. Wynika to z faktu, że typ parametru tags to Set<String>. Ten typ jest stały, ponieważ nie jest to MutableSet. Jednak interfejsy to standardowe klasy kolekcji, takie jak Set, List i Map. Dlatego też podstawowa implementacja może się zmieniać.

np. val set: Set<String> = mutableSetOf("foo"). Zmienna jest stała, a jej zadeklarowany typ nie jest zmienny, ale jej implementacja nadal jest zmienny. Kompilator Compose nie może mieć pewności o niezmienności tej klasy, ponieważ widzi tylko zadeklarowany typ. Oznacza to, że tags jest niestabilny.