Podczas uruchamiania aplikacji użytkownicy wyrabiają sobie pierwsze wrażenie. Uruchamianie aplikacji musi być szybkie, aby wczytywać i wyświetlać informacje potrzebne użytkownikowi do korzystania z aplikacji. Jeśli uruchamianie aplikacji trwa zbyt długo, użytkownicy mogą ją zamknąć, ponieważ zbyt długo czekają.
Do pomiaru czasu uruchamiania zalecamy używanie biblioteki Macrobenchmark do pomiaru uruchamiania. Biblioteka zawiera przegląd i szczegółowe ślady systemowe, dzięki którym możesz dokładnie zobaczyć, co się dzieje podczas uruchamiania.
Ślady systemowe zawierają przydatne informacje o tym, co się dzieje na urządzeniu. Pomagają one zrozumieć, co robi aplikacja podczas uruchamiania, i zidentyfikować potencjalne obszary optymalizacji.
Aby przeanalizować uruchamianie aplikacji:
- Skonfiguruj środowisko do rejestrowania śladów uruchamiania aplikacji.
- Zapoznaj się ze śladami systemowymi.
- Poruszaj się po raporcie śladów za pomocą profilerów Android Studio lub Perfetto.
Kroki analizy i optymalizacji uruchamiania
Podczas uruchamiania aplikacje często muszą wczytywać określone zasoby, które są kluczowe dla użytkowników. Zasoby nieistotne mogą poczekać na wczytanie do momentu zakończenia uruchamiania.
Aby dokonać kompromisu w zakresie wydajności, weź pod uwagę te kwestie:
Użyj biblioteki Macrobenchmark, aby zmierzyć czas potrzebny na wykonanie każdej operacji i zidentyfikować bloki, których wykonanie trwa długo.
Sprawdź, czy operacja wymagająca dużej ilości zasobów jest niezbędna do uruchomienia aplikacji. Jeśli operacja może poczekać, aż aplikacja zostanie w pełni narysowana, może to pomóc zminimalizować ograniczenia zasobów podczas uruchamiania.
Upewnij się, że ta operacja ma być wykonywana podczas uruchamiania aplikacji. Często niepotrzebne operacje mogą być wywoływane z kodu starszego lub bibliotek innych firm.
Jeśli to możliwe, przenieś długotrwałe operacje do tła. Procesy w tle mogą nadal wpływać na wykorzystanie procesora podczas uruchamiania.
Po dokładnym zbadaniu operacji możesz zdecydować, czy warto ją uwzględnić w procesie uruchamiania aplikacji, biorąc pod uwagę czas wczytywania. Pamiętaj, aby podczas modyfikowania przepływu pracy aplikacji uwzględnić możliwość regresji lub wprowadzenia zmian powodujących niezgodność.
Optymalizuj i ponownie mierz czas uruchamiania, aż będziesz zadowolony z jego wartości dla swojej aplikacji. Więcej informacji znajdziesz w artykule Używanie danych do wykrywania i diagnozowania problemów.
Pomiar i analiza czasu spędzonego na wykonywaniu głównych operacji
Gdy masz pełny ślad uruchamiania aplikacji, przyjrzyj się mu i zmierz czas potrzebny na wykonanie głównych operacji, takich jak bindApplication czy activityStart. Do analizy tych śladów zalecamy używanie Perfetto lub profilerów Android
Studio.
Sprawdź łączny czas spędzony podczas uruchamiania aplikacji, aby zidentyfikować operacje, które:
- zajmują dużo czasu i można je zoptymalizować. W przypadku wydajności liczy się każda milisekunda. Poszukaj na przykład
Choreographerczasów rysowania, początkowych czasów kompozycji, czasów wczytywania bibliotek,Bindertransakcji lub czasów wczytywania zasobów. Aby rozpocząć, sprawdź wszystkie operacje, które trwają dłużej niż 20 ms. - blokują wątek główny. Więcej informacji znajdziesz w artykule Poruszanie się po raporcie Systrace.
- nie muszą być wykonywane podczas uruchamiania.
- mogą poczekać, aż zostanie narysowana pierwsza klatka.
Aby znaleźć luki w wydajności, dokładniej zbadaj każdy z tych śladów.
Określanie operacji wymagających dużej ilości zasobów w wątku głównym
Zgodnie ze sprawdzonymi metodami operacje wymagające dużej ilości zasobów, takie jak operacje wejścia-wyjścia na plikach i dostęp do sieci, powinny być wykonywane poza wątkiem głównym. Jest to równie ważne podczas uruchamiania aplikacji, ponieważ operacje wymagające dużej ilości zasobów w wątku głównym mogą spowodować, że aplikacja przestanie odpowiadać, i opóźnić inne krytyczne operacje.
StrictMode.ThreadPolicy może pomóc w identyfikowaniu przypadków, w których operacje wymagające dużej ilości zasobów są wykonywane w wątku głównym.
Zgodnie ze sprawdzonymi metodami w przypadku kompilacji debugowych warto włączyć StrictMode, aby jak najszybciej wykryć problemy. Pokazuje to ten przykład:
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
...
if (BuildConfig.DEBUG)
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyDeath()
.build()
)
...
}
}
Użycie StrictMode.ThreadPolicy włącza zasady wątków we wszystkich kompilacjach debugowych i powoduje awarię aplikacji, gdy wykryte zostaną naruszenia zasad wątków. Dzięki temu trudno przeoczyć naruszenia zasad wątków.
TTID i TTFD
Aby sprawdzić, ile czasu zajmuje aplikacji wygenerowanie pierwszej klatki, zmierz czas do pierwszego wyświetlenia (TTID). Ten wskaźnik niekoniecznie odzwierciedla jednak czas, po którym użytkownik może zacząć korzystać z aplikacji. Wskaźnik czasu do pełnego wyświetlenia (TTFD) jest bardziej przydatny do pomiaru i optymalizacji ścieżek kodu niezbędnych do uzyskania w pełni użytecznego stanu aplikacji.
Strategie dotyczące zgłaszania, kiedy interfejs aplikacji jest w pełni narysowany, znajdziesz w artykule Zwiększanie dokładności pomiaru czasu uruchamiania.
Optymalizuj zarówno pod kątem TTID, jak i TTFD, ponieważ oba te wskaźniki są ważne w swoich obszarach. Krótki TTID pomaga użytkownikowi zobaczyć, że aplikacja rzeczywiście się uruchamia. Krótki TTFD jest ważny, aby użytkownik mógł szybko zacząć korzystać z aplikacji.
Analizowanie ogólnego stanu wątku
Wybierz czas uruchamiania aplikacji i sprawdź ogólne fragmenty wątków. Wątek główny musi być responsywny przez cały czas.
Narzędzia takie jak profiler Android Studio i Perfetto zapewniają szczegółowy przegląd wątku głównego i czasu spędzonego na każdym etapie. Więcej informacji o wizualizacji śladów Perfetto znajdziesz w dokumentacji interfejsu Perfetto.
Określanie głównych fragmentów stanu uśpienia wątku głównego
Jeśli aplikacja spędza dużo czasu w stanie uśpienia, prawdopodobnie oznacza to, że wątek główny aplikacji czeka na zakończenie pracy. Jeśli masz aplikację wielowątkową, określ wątek, na który czeka wątek główny, i rozważ optymalizację tych operacji. Warto też sprawdzić, czy nie ma niepotrzebnych konfliktów blokad, które powodują opóźnienia na ścieżce krytycznej.
Ograniczanie blokowania wątku głównego i nieprzerwanego uśpienia
Sprawdź każdy przypadek, w którym wątek główny przechodzi w stan zablokowany. W Perfetto i profilerze Studio jest to oznaczone pomarańczowym wskaźnikiem na osi czasu stanu wątku. Określ operacje, sprawdź, czy są one oczekiwane lub czy można ich uniknąć, i w razie potrzeby je zoptymalizuj.
Uśpienie przerywalne związane z operacjami wejścia-wyjścia może być bardzo dobrą okazją do poprawy. Inne procesy wykonujące operacje wejścia-wyjścia, nawet jeśli są to niezwiązane aplikacje, mogą konkurować z operacjami wejścia-wyjścia wykonywanymi przez aplikację na pierwszym planie.
Skracanie czasu uruchamiania
Gdy znajdziesz możliwość optymalizacji, sprawdź możliwe rozwiązania, które pomogą skrócić czas uruchamiania:
- Wczytuj treści leniwie i asynchronicznie, aby przyspieszyć TTID.
- Zminimalizuj wywoływanie funkcji, które wykonują wywołania Binder. Jeśli nie można ich uniknąć, zoptymalizuj te wywołania, buforując wartości zamiast powtarzać wywołania lub przenosząc pracę nieblokującą do wątków w tle.
- Aby przyspieszyć uruchamianie aplikacji, możesz jak najszybciej wyświetlić użytkownikowi coś, co wymaga minimalnego renderowania, aż do momentu, gdy reszta ekranu zostanie wczytana.
- Utwórz i dodaj do aplikacji profil uruchamiania.
- Użyj biblioteki Jetpack App Startup, aby usprawnić inicjowanie komponentów podczas uruchamiania aplikacji.
Analizowanie wydajności interfejsu
Uruchamianie aplikacji obejmuje ekran powitalny i czas wczytywania strony głównej. Aby zoptymalizować uruchamianie aplikacji, sprawdź ślady, aby dowiedzieć się, ile czasu zajmuje narysowanie interfejsu.
Ograniczanie pracy podczas inicjowania
Wczytywanie niektórych klatek może trwać dłużej niż innych. Są one uważane za kosztowne rysowanie dla aplikacji.
Aby zoptymalizować inicjowanie:
- Określ priorytet dla powolnych faz kompozycji i układu oraz wybierz je do ulepszenia.
- Zbadaj każde ostrzeżenie z Perfetto i alert z Systrace, dodając niestandardowe zdarzenia śledzenia, aby zmniejszyć liczbę kosztownych rysowań i opóźnień.
Pomiar danych klatek
Dane klatek można mierzyć na kilka sposobów. Oto 5 głównych metod zbierania danych:
- Zbieranie lokalne za pomocą
dumpsys gfxinfo: nie wszystkie klatki zaobserwowane w danych dumpsys są odpowiedzialne za powolne renderowanie aplikacji lub mają wpływ na użytkowników. Jest to jednak dobry sposób na sprawdzenie trendu ogólnej wydajności w różnych cyklach wydawania. Więcej informacji o używaniugfxinfoiframestatsdo integrowania pomiarów wydajności interfejsu z testami znajdziesz w artykule Podstawy testowania aplikacji na Androida. - Zbieranie danych w polu za pomocą JankStats: zbieraj czasy renderowania klatek z określonych części aplikacji za pomocą biblioteki JankStats oraz rejestruj i analizuj dane.
- W testach za pomocą Macrobenchmark (Perfetto w tle)
- Perfetto FrameTimeline: w Androidzie 12 (poziom API 31) lub nowszym możesz zbierać dane z osi czasu klatek ze śladu Perfetto, aby określić, które zadanie powoduje spadek liczby klatek. Może to być pierwszy krok do zdiagnozowania przyczyny spadku liczby klatek.
- Profiler Android Studio do wyk1}wykrywania zacięć
Sprawdzanie czasu wczytywania głównej aktywności
Główna aktywność aplikacji może zawierać dużą ilość informacji wczytywanych z wielu źródeł. Sprawdź interfejs Activity strony głównej, a w szczególności zdarzenie Choreographer#doFrame.
- Użyj
reportFullyDrawn, aby poinformować system, że aplikacja jest już w pełni narysowana, co pozwoli na optymalizację. - Mierz uruchamianie aktywności i aplikacji za pomocą
StartupTimingMetricz biblioteką Macrobenchmark. - Sprawdź spadki liczby klatek.
- Określ układy, których renderowanie lub pomiar trwa długo.
- Określ zasoby, których wczytywanie trwa długo.
- Określ niepotrzebne elementy interfejsu, które są uwzględnione w początkowej kompozycji.
Aby zoptymalizować czas wczytywania głównej aktywności, rozważ te możliwe rozwiązania:
- Zadbaj o to, aby początkowa kompozycja była jak najlżejsza. Więcej informacji znajdziesz w artykule Jetpack Compose Performance.
- Dodaj niestandardowe punkty śledzenia, aby uzyskać więcej informacji o spadkach liczby klatek i złożonych układach.
- Zminimalizuj liczbę i rozmiar zasobów bitmapowych wczytywanych podczas uruchamiania. Więcej informacji znajdziesz w artykule Optymalizowanie obrazów bitmapowych.
Jeśli używasz Jetpack Compose, rozważ użycie kompozycji warunkowej, aby odłożyć wczytywanie części interfejsu, które nie są od razu widoczne po uruchomieniu, takich jak ekrany błędów, opcjonalne szczegóły czy karty dodatkowe. Otaczając złożone komponenty prostym sprawdzeniem stanu, unikasz wykonywania logiki kompozycji podczas krytycznego okna uruchamiania, co sprawia, że początkowy układ jest lekki.
var shouldLoad by remember {mutableStateOf(false)} if (shouldLoad) { MyComposable() }Wczytaj elementy kompozycyjne w bloku warunkowym, modyfikując
shouldLoad:LaunchedEffect(Unit) { shouldLoad = true }Spowoduje to ponowną kompozycję, która obejmuje kod w bloku warunkowym w pierwszym fragmencie.
Więcej informacji o optymalizacji wydajności Compose znajdziesz w artykule Sprawdzone metody.
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Rejestrowanie danych Macrobenchmark
- Przegląd pomiaru wydajności aplikacji * Zablokowane klatki