Tworzenie profili podstawowych

Profile podstawowe są niezbędne do maksymalizacji wydajności Jetpack Compose. Wstępne skompilowanie najważniejszych ścieżek użytkownika pomaga zapewnić płynne renderowanie interfejsu Compose.

Automatycznie generuj profile dla każdej wersji aplikacji za pomocą biblioteki Jetpack MacrobenchmarkBaselineProfileRule. Zalecamy używanie wersji com.android.tools.build:gradle:8.0.0 lub nowszej, aby korzystać z ulepszeń kompilacji podczas używania profili podstawowych.

Oto ogólne kroki tworzenia nowego profilu podstawowego:

  1. Skonfiguruj moduł profilu podstawowego.
  2. Zdefiniuj test JUnit, który pomoże wygenerować profile podstawowe.
  3. Dodaj główne ścieżki użytkownika, które chcesz optymalizować.
  4. Wygeneruj profil podstawowy.

Po wygenerowaniu profilu podstawowego przeprowadź test porównawczy na urządzeniu fizycznym, aby zmierzyć wzrost szybkości.

Tworzenie nowego profilu podstawowego za pomocą wtyczki AGP w wersji 8.2 lub nowszej

Najprostszym sposobem utworzenia nowego profilu podstawowego jest użycie szablonu modułu profilu podstawowego, który jest dostępny od Androida Studio Iguana i Androida Gradle Plugin (AGP) 8.2.

Szablon modułu Generator profili bazowych Androida Studio automatyzuje tworzenie nowego modułu do generowania i testowania profili bazowych. Uruchomienie szablonu generuje większość typowej konfiguracji kompilacji, generowanie profilu podstawowego i kod weryfikacyjny. Szablon tworzy kod do generowania i testowania profili podstawowych, aby mierzyć uruchamianie aplikacji.

Konfigurowanie modułu profilu podstawowego

Aby uruchomić szablon modułu Profil podstawowy, wykonaj te czynności:

  1. Wybierz Plik > Nowy > Nowy moduł.
  2. Wybierz szablon Generator profilu podstawowego w panelu Szablony i skonfiguruj go:
    Ilustracja 1. Szablon modułu generatora profilu podstawowego.
    Szablon zawiera te pola:
    • Aplikacja docelowa: aplikacja, dla której generowany jest profil podstawowy. Jeśli w projekcie masz tylko jeden moduł aplikacji, na tej liście będzie tylko 1 element.
    • Nazwa modułu: nazwa modułu profilu podstawowego, który jest tworzony.
    • Nazwa pakietu: nazwa pakietu, który chcesz przypisać do modułu profilu podstawowego.
    • Język: czy wygenerowany kod ma być w języku Kotlin czy Java.
    • Język konfiguracji kompilacji: czy w skryptach konfiguracji kompilacji chcesz używać skryptu Kotlin (KTS) czy Groovy.
    • Użyj urządzenia zarządzanego przez Gradle: czy do testowania aplikacji używasz urządzeń zarządzanych przez Gradle.
  3. Kliknij Zakończ, aby utworzyć nowy moduł. Jeśli używasz kontroli źródła, może pojawić się prośba o dodanie nowo utworzonych plików modułu do kontroli źródła.

Definiowanie generatora profilu podstawowego

Nowo utworzony moduł zawiera testy generowania i testowania profilu podstawowego oraz testowania tylko podstawowego uruchamiania aplikacji. Zalecamy rozszerzenie tych informacji o CUJ i zaawansowane procesy uruchamiania. Upewnij się, że wszystkie testy związane z uruchamianiem aplikacji znajdują się w bloku rule z ustawioną wartością includeInStartupProfile na true. Z kolei aby uzyskać optymalną wydajność, upewnij się, że wszystkie testy niezwiązane z uruchamianiem aplikacji nie są uwzględnione w profilu uruchamiania. Optymalizacje uruchamiania aplikacji służą do definiowania specjalnej części profilu podstawowego, zwanej profilem uruchamiania.

Ułatwia to utrzymanie, jeśli wyodrębnisz te CUJ poza wygenerowany profil podstawowy i kod testu porównawczego, aby można było ich używać w obu przypadkach. Oznacza to, że zmiany w CUJ są stosowane w spójny sposób.

Generowanie i instalowanie profilu podstawowego

Szablon modułu profilu podstawowego dodaje nową konfigurację uruchamiania, która umożliwia wygenerowanie profilu podstawowego. Jeśli używasz wersji produktu, Android Studio tworzy wiele konfiguracji uruchamiania, dzięki czemu możesz generować osobne profile bazowe dla każdej wersji.

Konfiguracja uruchomienia Generowanie profilu podstawowego.
Rysunek 2. Uruchomienie tej konfiguracji spowoduje wygenerowanie profilu podstawowego.

Po zakończeniu działania konfiguracji Generate Baseline Profile (Generuj profil podstawowy) kopiuje ona wygenerowany profil podstawowy do pliku src/variant/generated/baselineProfiles/baseline-prof.txt w profilowanym module. Opcje wariantów to rodzaj kompilacji do publikacji lub wariant kompilacji obejmujący rodzaj kompilacji do publikacji.

Wygenerowany profil podstawowy jest pierwotnie tworzony w build/outputs. Pełna ścieżka zależy od wariantu lub wersji profilowanej aplikacji oraz od tego, czy do profilowania używasz urządzenia zarządzanego przez Gradle czy podłączonego urządzenia. Jeśli użyjesz nazw używanych przez kod i konfiguracje kompilacji wygenerowane przez szablon, profil podstawowy zostanie utworzony w pliku build/outputs/managed_device_android_test_additional_output/nonminifiedrelease/pixel6Api31/BaselineProfileGenerator_generate-baseline-prof.txt. Z tą wersją wygenerowanego profilu podstawowego prawdopodobnie nie będziesz wchodzić w interakcje bezpośrednio, chyba że ręcznie skopiujesz ją do modułów docelowych (nie jest to zalecane).

Tworzenie nowego profilu podstawowego za pomocą AGP 8.1

Jeśli nie możesz użyć szablonu modułu profilu podstawowego, użyj szablonu modułu Macrobenchmark i wtyczki Gradle profilu podstawowego, aby utworzyć nowy profil podstawowy. Zalecamy korzystanie z tych narzędzi od wersji Android Studio Giraffe i wtyczki Androida do obsługi Gradle 8.1.

Aby utworzyć nowy profil podstawowy za pomocą szablonu modułu Macrobenchmark i wtyczki Gradle Baseline Profile:

  1. Skonfiguruj moduł Macrobenchmark w projekcie Gradle.
  2. Zdefiniuj nową klasę o nazwie BaselineProfileGenerator:

    class BaselineProfileGenerator {
        @get:Rule
        val baselineProfileRule = BaselineProfileRule()
    
        @Test
        fun startup() = baselineProfileRule.collect(
            packageName = "com.example.app",
            profileBlock = {
                startActivityAndWait()
            }
        )
    }
    

    Generator może zawierać interakcje z aplikacją wykraczające poza jej uruchomienie. Pozwala to zoptymalizować wydajność aplikacji w czasie działania, np. przewijanie list, uruchamianie animacji i poruszanie się w Activity. Zobacz inne przykłady testów, które wykorzystują @BaselineProfileRule do ulepszania kluczowych ścieżek użytkowników.

  3. Dodaj wtyczkę Gradle profilu podstawowego (libs.plugins.androidx.baselineprofile). Ułatwia ona generowanie profili podstawowych i zarządzanie nimi w przyszłości.

  4. Aby wygenerować profil podstawowy, uruchom zadania Gradle :app:generateBaselineProfile lub :app:generateVariantBaselineProfile w terminalu.

    Uruchom generator jako test z instrumentacją na urządzeniu fizycznym z dostępem do roota, emulatorze lub urządzeniu zarządzanym przez Gradle. Jeśli używasz urządzenia zarządzanego przez Gradle, ustaw aosp jako systemImageSource, ponieważ generator profilu podstawowego wymaga dostępu do roota.

    Po zakończeniu zadania generowania profil podstawowy jest kopiowany do folderu app/src//generated/baselineProfiles.

Tworzenie nowego profilu podstawowego bez szablonów

Zalecamy utworzenie profilu podstawowego za pomocą szablonu modułu profilu podstawowego w Android Studio (preferowane) lub szablonu Macrobenchmark, ale możesz też użyć samego wtyczki Gradle profilu podstawowego. Więcej informacji o wtyczce Gradle do obsługi profilu podstawowego znajdziesz w artykule Konfigurowanie generowania profilu podstawowego.

Aby utworzyć profil podstawowy bezpośrednio za pomocą wtyczki Gradle Baseline Profile:

  1. Utwórz nowy moduł com.android.test, np. :baseline-profile.
  2. Skonfiguruj plik build.gradle.kts dla usługi :baseline-profile:

    1. Zastosuj wtyczkę androidx.baselineprofile.
    2. Sprawdź, czy targetProjectPath wskazuje moduł :app.
    3. Opcjonalnie dodaj urządzenie zarządzane przez Gradle (GMD). W przykładzie poniżej jest to pixel6Api31. Jeśli nie zostanie określone, wtyczka używa podłączonego urządzenia, emulowanego lub fizycznego.
    4. Zastosuj wybraną konfigurację, jak pokazano w tym przykładzie.

    Kotlin

    plugins {
        id("com.android.test")
        id("androidx.baselineprofile")
    }
    
    android {
        defaultConfig {
            ...
        }
    
        // Point to the app module, the module that you're generating the Baseline Profile for.
        targetProjectPath = ":app"
        // Configure a GMD (optional).
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device = "Pixel 6"
                apiLevel = 31
                systemImageSource = "aosp"
            }
        }
    }
    
    dependencies { ... }
    
    // Baseline Profile Gradle plugin configuration. Everything is optional. This
    // example uses the GMD added earlier and disables connected devices.
    baselineProfile {
        // Specifies the GMDs to run the tests on. The default is none.
        managedDevices += "pixel6Api31"
        // Enables using connected devices to generate profiles. The default is
        // `true`. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices = false
    }

    Dynamiczny

    plugins {
        id 'com.android.test'
        id 'androidx.baselineprofile'
    }
    
    android {
        defaultConfig {
            ...
        }
    
        // Point to the app module, the module that you're generating the Baseline Profile for.
        targetProjectPath ':app'
        // Configure a GMD (optional).
        testOptions.managedDevices.devices {
            pixel6Api31(com.android.build.api.dsl.ManagedVirtualDevice) {
                device 'Pixel 6'
                apiLevel 31
                systemImageSource 'aosp'
            }
        }
    }
    
    dependencies { ... }
    
    // Baseline Profile Gradle plugin configuration. Everything is optional. This
    // example uses the GMD added earlier and disables connected devices.
    baselineProfile {
        // Specifies the GMDs to run the tests on. The default is none.
        managedDevices ['pixel6Api31']
        // Enables using connected devices to generate profiles. The default is
        // `true`. When using connected devices, they must be rooted or API 33 and
        // higher.
        useConnectedDevices false
    }
  3. Utwórz test profilu podstawowego w module testowym :baseline-profile. Poniższy przykład to test, który generuje profil podstawowy na potrzeby uruchamiania aplikacji.

        class BaselineProfileGenerator {
        @get:Rule
        val baselineProfileRule = BaselineProfileRule()
    
        @Test
        fun startup() = baselineProfileRule.collect(
            packageName = "com.example.app",
            profileBlock = {
                uiAutomator { startApp(PACKAGE_NAME) }
            }
        )
    }
    
  4. Zaktualizuj plik build.gradle.kts w module aplikacji, np. :app.

    1. Zastosuj wtyczkę androidx.baselineprofile.
    2. Dodaj zależność baselineProfile do modułu :baseline-profile.

    Kotlin

    plugins {
        id("com.android.application")
        id("androidx.baselineprofile")
    }
    
    android {
        // There are no changes to the `android` block.
        ...
    }
    
    dependencies {
        ...
        // Add a `baselineProfile` dependency on the `:baseline-profile` module.
        baselineProfile(project(":baseline-profile"))
    }

    Dynamiczny

    plugins {
        id 'com.android.application'
        id 'androidx.baselineprofile'
    }
    
    android {
        // No changes to the `android` block.
        ...
    }
    
    dependencies {
        ...
        // Add a `baselineProfile` dependency on the `:baseline-profile` module.
        baselineProfile ':baseline-profile'
    }
  5. Wygeneruj profil, uruchamiając zadania Gradle :app:generateBaselineProfilelub :app:generateVariantBaselineProfile.

  6. Po zakończeniu zadania generowania profil podstawowy jest kopiowany do folderu app/src/variant/generated/baselineProfiles.

Testowanie profilu podstawowego

Aby porównać profil podstawowy, utwórz nową konfigurację testu z instrumentacją na Androidzie, korzystając z działania na marginesie, które wykonuje testy porównawcze zdefiniowane w pliku StartupBenchmarks.kt. Więcej informacji o testach porównawczych znajdziesz w artykułach Tworzenie klasy MacrobenchmarkTestowanie profili podstawowych za pomocą biblioteki Macrobenchmark.

Rysunek 3. Uruchom testy Androida z obszaru obok wiersza kodu.

Gdy uruchomisz to w Android Studio, dane wyjściowe kompilacji będą zawierać szczegóły dotyczące wzrostu szybkości, jaki zapewnia profil podstawowy:

StartupBenchmarks_startupCompilationBaselineProfiles
timeToInitialDisplayMs   min 161.8,   median 178.9,   max 194.6
StartupBenchmarks_startupCompilationNone
timeToInitialDisplayMs   min 184.7,   median 196.9,   max 202.9

Uwzględnij wszystkie wymagane ścieżki kodu

Oto 2 kluczowe wskaźniki pomiaru czasu uruchamiania aplikacji:

TTFD jest zgłaszany po wywołaniu metody reportFullyDrawn interfejsu ComponentActivity. Jeśli funkcja reportFullyDrawn nie zostanie nigdy wywołana, zamiast tego zostanie zgłoszony identyfikator TTID. Może być konieczne opóźnienie wywołania funkcji reportFullyDrawn do momentu zakończenia ładowania asynchronicznego. Jeśli na przykład interfejs zawiera dynamiczną listę leniwą, może ona być wypełniana przez zadanie w tle, które kończy się po pierwszym narysowaniu listy, a więc po oznaczeniu interfejsu jako w pełni narysowanego. W takich przypadkach kod, który jest uruchamiany po osiągnięciu przez interfejs stanu pełnego wyrenderowania, nie jest uwzględniany w profilu podstawowym.

Aby uwzględnić populację listy w profilu podstawowym, uzyskaj FullyDrawnReporter za pomocą getFullyDrawnReporter i dodaj do niego reportera w kodzie aplikacji. Zwolnij reportera, gdy zadanie w tle zakończy wypełnianie listy. Funkcja FullyDrawnReporter nie wywołuje metody reportFullyDrawn, dopóki nie zostaną zwolnione wszystkie obiekty reportera. W ten sposób profil podstawowy będzie zawierać ścieżki kodu wymagane do wypełnienia listy. Nie zmienia to zachowania aplikacji w przypadku użytkownika, ale pozwala profilowi podstawowemu uwzględnić wszystkie niezbędne ścieżki kodu.

Aby wskazać stan pełnego wyrenderowania, użyj tych interfejsów API Compose:

  • ReportDrawn oznacza, że komponent jest od razu gotowy do interakcji.
  • ReportDrawnWhen przyjmuje predykat, np. list.count > 0, aby wskazać, kiedy komponent jest gotowy do interakcji.
  • ReportDrawnAfter przyjmuje metodę zawieszającą, która po zakończeniu wskazuje, że komponent jest gotowy do interakcji.