Tworzenie profili podstawowych

Automatycznie generuj profile dla każdej wersji aplikacji za pomocą biblioteki Jetpack Macrobenchmark i BaselineProfileRule. Zalecamy używanie wersji com.android.tools.build:gradle:8.0.0 lub nowszej, która zapewnia lepszą kompilację podczas korzystania z 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 najważniejsze ścieżki użytkownika, które chcesz zoptymalizować.
  4. Wygeneruj profil podstawowy.

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

Tworzenie nowego profilu podstawowego za pomocą AGP 8.2 lub nowszego

Najłatwiejszym sposobem utworzenia nowego profilu podstawowego jest użycie szablonu modułu profilu podstawowego, który jest dostępny od wersji Android Studio Iguana i wtyczki Androida do obsługi Gradle (AGP) 8.2.

Szablon modułu generatora profilu podstawowego w Android Studio automatyzuje tworzenie nowego modułu do generowania i testowania porównawczego profili podstawowych. Uruchomienie szablonu generuje większość typowej konfiguracji kompilacji, profilu podstawowego oraz kodu weryfikacyjnego. Szablon tworzy kod do generowania i testowania porównawczego profili podstawowych w celu pomiaru czasu uruchamiania aplikacji.

Konfigurowanie modułu profilu podstawowego

Aby uruchomić szablon modułu profilu podstawowego, wykonaj te czynności:

  1. Kliknij File > New > New Module (Plik > Nowy > Nowy moduł).
  2. W panelu Templates (Szablony) wybierz szablon Baseline Profile Generator (Generator profilu podstawowego) i skonfiguruj go:
    Figure 1. (Rysunek 1.) Szablon modułu generatora profilu podstawowego.

    Pola w szablonie są następujące:

    • Target application (Aplikacja docelowa): określa, dla której aplikacji ma zostać wygenerowany profil podstawowy. Jeśli w projekcie masz tylko 1 moduł aplikacji, na tej liście będzie tylko 1 element.
    • Module name (Nazwa modułu): nazwa, którą chcesz nadać tworzonemu modułowi profilu podstawowego.
    • Package name (Nazwa pakietu): nazwa pakietu, którą chcesz nadać modułowi profilu podstawowego.
    • Language (Język): czy wygenerowany kod ma być w języku Kotlin czy Java.
    • Build configuration language (Język konfiguracji kompilacji): czy w skryptach konfiguracji kompilacji chcesz używać skryptu Kotlin (KTS) czy Groovy.
    • Use Gradle-managed device (Użyj urządzenia zarządzanego przez Gradle): jeśli do testowania aplikacji używasz urządzeń zarządzanych przez Gradle.
  3. Kliknij Finish (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, które służą do generowania i testowania porównawczego profilu podstawowego oraz do testowania tylko podstawowego uruchamiania aplikacji. Zalecamy rozszerzenie tych testów o najważniejsze ścieżki użytkownika 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ędniane w profilu uruchamiania. Optymalizacje uruchamiania aplikacji służą do definiowania specjalnej części profilu podstawowego, zwanej profilem uruchamiania.

Aby ułatwić utrzymanie, warto wyodrębnić te najważniejsze ścieżki użytkownika 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 najważniejszych ścieżkach użytkownika są stosowane konsekwentnie.

Generowanie i instalowanie profilu podstawowego

Szablon modułu profilu podstawowego dodaje nową konfigurację uruchamiania, która służy do generowania profilu podstawowego. Jeśli używasz wariantów produktu, Android Studio tworzy wiele konfiguracji uruchamiania, dzięki czemu możesz generować osobne profile podstawowe dla każdego wariantu.

Konfiguracja uruchomienia Generowanie profilu podstawowego.
Rysunek 2. Uruchomienie tej konfiguracji generuje profil podstawowy.

Po zakończeniu konfiguracji uruchamiania Generate Baseline Profile (Wygeneruj profil podstawowy) wygenerowany profil podstawowy jest kopiowany do pliku src/variant/generated/baselineProfiles/baseline-prof.txt w profilowanym module. Opcje wariantu to rodzaj kompilacji do publikacji lub wariant kompilacji obejmujący rodzaj kompilacji do publikacji.

Wygenerowany profil podstawowy jest pierwotnie tworzony w katalogu build/outputs. Pełna ścieżka jest określana przez wariant lub wersję profilowanej aplikacji oraz przez to, czy do profilowania używasz urządzenia zarządzanego przez Gradle czy podłączonego urządzenia. Jeśli używasz nazw używanych przez kod i konfiguracje kompilacji wygenerowane przez szablon, profil podstawowy jest tworzony w pliku build/outputs/managed_device_android_test_additional_output/nonminifiedrelease/pixel6Api31/BaselineProfileGenerator_generate-baseline-prof.txt. Prawdopodobnie nie będziesz musiał(-a) bezpośrednio korzystać z tej wersji wygenerowanego profilu podstawowego, chyba że ręcznie skopiujesz go do modułów docelowych (niezalecane).

Tworzenie nowego profilu podstawowego za pomocą AGP 8.1

Jeśli nie możesz użyć szablonu modułu profilu podstawowego, utwórz nowy profil podstawowy za pomocą szablonu modułu Macrobenchmark i wtyczki Gradle profilu podstawowego. Zalecamy korzystanie z tych narzędzi od wersji Android Studio Giraffe i AGP 8.1.

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

  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 uruchamianie aplikacji. Dzięki temu możesz zoptymalizować wydajność aplikacji w czasie działania, np. przewijanie list, uruchamianie animacji i nawigowanie w obrębie Activity. Zobacz inne przykłady testów, które używają @BaselineProfileRule do poprawy najważniejszych ścieżek użytkownika.

  3. Dodaj wtyczkę Gradle profilu podstawowego (libs.plugins.androidx.baselineprofile). Wtyczka ułatwia generowanie profili podstawowych i ich utrzymywanie w przyszłości.

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

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

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

Tworzenie nowego profilu podstawowego bez szablonów

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

Aby utworzyć profil podstawowy bezpośrednio za pomocą wtyczki Gradle profilu podstawowego:

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

    1. Zastosuj wtyczkę androidx.baselineprofile.
    2. Upewnij się, że targetProjectPath wskazuje moduł :app.
    3. Opcjonalnie dodaj urządzenie zarządzane przez Gradle (GMD). W tym przykładzie 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.

    Kotlin

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

    Java

    public class BaselineProfileGenerator {
    
        @Rule
        Public BaselineProfileRule baselineRule = new BaselineProfileRule();
    
        @Test
        Public void startupBaselineProfile() {
            baselineRule.collect(
                "com.myapp",
                (scope -> {
                    scope.startActivityAndWait();
                    Return Unit.INSTANCE;
                })
            )
        }
    }
  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:generateBaselineProfile lub :app:generateVariantBaselineProfile.

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

Tworzenie nowego profilu podstawowego za pomocą AGP 7.3–7.4

Profile podstawowe można generować za pomocą AGP 7.3–7.4, ale zdecydowanie zalecamy uaktualnienie do co najmniej AGP 8.1, aby móc korzystać z wtyczki Gradle profilu podstawowego i jej najnowszych funkcji.

Jeśli musisz utworzyć profile podstawowe za pomocą AGP 7.3–7.4, wykonaj te same czynności co w przypadku AGP 8.1, z tymi wyjątkami:

Ręczne stosowanie wygenerowanych reguł

Generator profilu podstawowego tworzy na urządzeniu plik tekstowy w formacie HRF (Human Readable Format) i kopiuje go na komputer hosta. Aby zastosować wygenerowany profil do kodu:

  1. Znajdź plik HRF w folderze kompilacji modułu, w którym generujesz profil: [module]/build/outputs/managed_device_android_test_additional_output/[device].

    Profile są zgodne ze wzorcem nazewnictwa [class name]-[test method name]-baseline-prof.txt, który wygląda tak: BaselineProfileGenerator-startup-baseline-prof.txt.

  2. Skopiuj wygenerowany profil do katalogu src/main/ i zmień nazwę pliku na baseline-prof.txt.

  3. Aby włączyć lokalną kompilację profilu podstawowego, gdy profile w chmurze są niedostępne, dodaj zależność do biblioteki ProfileInstaller w pliku build.gradle.kts aplikacji. Jest to jedyny sposób na lokalne wczytanie profilu podstawowego.

    dependencies {
         implementation("androidx.profileinstaller:profileinstaller:1.4.1")
    }
    
  4. Skompiluj wersję produkcyjną aplikacji, podczas gdy zastosowane reguły HRF są kompilowane do postaci binarnej i dołączane do pliku APK lub AAB. Następnie rozpowszechnij aplikację w zwykły sposób.

Testowanie porównawcze profilu podstawowego

Aby przeprowadzić test porównawczy profilu podstawowego, utwórz nową konfigurację uruchamiania testu instrumentowanego na Androida za pomocą działania w rynnie, które wykonuje testy porównawcze zdefiniowane w pliku StartupBenchmarks.kt lub StartupBencharks.java. Więcej informacji o testach porównawczych znajdziesz w artykułach Tworzenie klasy Macrobenchmark i Automatyzowanie pomiarów za pomocą biblioteki Macrobenchmark.

Rysunek 3. Uruchamianie testów na Androida za pomocą działania w rynnie action.

Gdy uruchomisz tę konfigurację w Android Studio, dane wyjściowe kompilacji będą zawierać szczegóły dotyczące poprawy szybkości, jaką 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

Przechwytywanie wszystkich wymaganych ścieżek kodu

Dwa kluczowe wskaźniki do pomiaru czasu uruchamiania aplikacji:

Czas do początkowego wyświetlania (TTID)
Czas potrzebny do wyświetlenia pierwszej klatki interfejsu aplikacji.
Czas do pełnego wyświetlenia (TTFD)
TTID plus czas potrzebny do wyświetlenia treści, które są ładowane asynchronicznie po wyświetleniu pierwszej klatki.

TTFD jest zgłaszany po wywołaniu reportFullyDrawn() metody ComponentActivity. Jeśli metoda reportFullyDrawn() nie zostanie nigdy wywołana, zamiast niej zgłaszany jest TTID. Może być konieczne opóźnienie wywołania metody reportFullyDrawn() do momentu zakończenia ładowania asynchronicznego. Jeśli na przykład interfejs zawiera listę dynamiczną, taką jak RecyclerView lub lista leniwa, lista może być wypełniana przez zadanie w tle, które kończy się po pierwszym narysowaniu listy, a tym samym 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 narysowania, nie jest uwzględniany w profilu podstawowym.

Aby uwzględnić wypełnianie listy w profilu podstawowym, pobierz FullyDrawnReporter za pomocą getFullyDrawnReporter() i dodaj do niego reportera w kodzie aplikacji. Zwolnij reportera, gdy zadanie w tle zakończy wypełnianie listy. Metoda reportFullyDrawn() nie jest wywoływana przez FullyDrawnReporter do momentu zwolnienia wszystkich reporterów. Dzięki temu profil podstawowy 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.

Jeśli Twoja aplikacja używa Jetpack Compose, użyj tych interfejsów API, aby wskazać stan pełnego narysowania:

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