Biblioteka JankStats pomaga śledzić i analizować problemy z wydajnością aplikacji. Jank odnosi się do klatek aplikacji, których renderowanie trwa zbyt długo, a biblioteka JankStats zawiera raporty o statystykach zaciętych aplikacji.
Uprawnienia
JankStats rozszerza możliwości istniejącej platformy Androida, Interfejs FrameMetrics API na Androidzie 7 (poziom interfejsu API 24) i nowszych lub OnPreDrawListener wcześniej wersji. Mechanizmy te mogą pomóc aplikacjom śledzić, ile czasu zajmuje gotowe. Biblioteka JanksStats oferuje dwie dodatkowe możliwości, dzięki którym bardziej dynamiczny i łatwiejszy w użyciu: błędna heurystyka i stan interfejsu.
Heurystyka stymulująca
Możesz wykorzystać FrameMetrics do śledzenia czasu trwania klatek, ale FrameMetrics nie nie pomoże Ci w znalezieniu problemu. JankStats ma natomiast które pozwalają określić moment zacinania się aplikacji. raporty są bardziej przydatne.
Stan interfejsu
Często dobrze jest poznać kontekst problemów z wydajnością aplikacji. Jeśli np. tworzysz złożoną aplikację na wiele urządzeń, która korzysta z FrameMetrics i stwierdzisz, że Twoja aplikacja często ma wyjątkowo niezdrowe ramki, umieścić te informacje w kontekście, wiedząc, gdzie wystąpił problem, co robi użytkownik i jak to powieli.
JankStats rozwiązuje ten problem, wprowadzając interfejs API state, który pozwala
komunikuje się z biblioteką, aby udostępniać informacje o aktywności w aplikacji; Kiedy
JankStats rejestruje informacje o nieprawidłowej ramce, w tym bieżący stan
aplikacji w raportach o bałaganach.
Wykorzystanie
Aby zacząć korzystać z JankStats, utwórz i włącz bibliotekę dla każdego
Window Każdy obiekt JankStats śledzi dane
tylko w obrębie Window. Utworzenie instancji biblioteki wymaga instancji Window
wraz z OnFrameListener
służą do wysyłania wskaźników do klienta. Wywołanie funkcji detektora przy użyciu parametru
FrameData w każdej klatce
oraz szczegóły:
- Czas rozpoczęcia renderowania
- Czas trwania
- Określa, czy ramka ma być uznawana za zacinającą się.
- Zbiór par ciągu znaków zawierający informacje o stanie aplikacji w trakcie klatki
Aby statystyki Jank były bardziej przydatne, aplikacje powinny umieszczać w bibliotece dane
istotne informacje o stanie UI na potrzeby raportowania w FrameData. Możesz to zrobić
przez
PerformanceMetricsState
API (nie bezpośrednio JankStats), gdzie cała logika zarządzania stanami oraz interfejsy API
na żywo.
Inicjalizacja
Aby zacząć korzystać z biblioteki JankStats, najpierw dodaj zależność JankStats do Plik Gradle:
implementation "androidx.metrics:metrics-performance:1.0.0"
Następnie zainicjuj i włącz JankStats dla każdego elementu Window. Warto też wstrzymać
Śledzenie JankStats, gdy aktywność rozpoczyna się w tle. Utwórz i włącz
obiekt JankStats w sekcji Aktywność zastępuje:
class JankLoggingActivity : AppCompatActivity() {
private lateinit var jankStats: JankStats
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
// metrics state holder can be retrieved regardless of JankStats initialization
val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root)
// initialize JankStats for current window
jankStats = JankStats.createAndTrack(window, jankFrameListener)
// add activity name as state
metricsStateHolder.state?.putState("Activity", javaClass.simpleName)
// ...
}
W przykładzie powyżej wstrzyknięto informacje o stanie bieżącego Działanie po utworzeniu obiektu JankStats. Wszystkie przyszłe raporty FrameData utworzona dla tego obiektu JankStats zawiera teraz również informacje o aktywności.
Metoda JankStats.createAndTrack odwołuje się do Window
który jest serwerem proxy hierarchii widoków wewnątrz Window, a także
dla samej Window. Funkcja jankFrameListener jest wywoływana w tym samym wątku, który jest używany
aby przekazywać te informacje z platformy do narzędzia JankStats wewnętrznie.
Aby włączyć śledzenie i raportowanie dowolnego obiektu JankStats,
Zadzwoń pod numer isTrackingEnabled = true. Mimo że ta opcja jest domyślnie włączona,
wstrzymanie aktywności wyłącza śledzenie. W takim przypadku ponownie włącz
śledzenie, zanim przejdziesz dalej. Aby wyłączyć śledzenie, zadzwoń pod numer isTrackingEnabled = false.
override fun onResume() {
super.onResume()
jankStats.isTrackingEnabled = true
}
override fun onPause() {
super.onPause()
jankStats.isTrackingEnabled = false
}
Raportowanie
Biblioteka JankStats przekazuje wszystkie dane śledzenia, dla każdej klatki,
OnFrameListener
dla włączonych obiektów JankStats. Aplikacje mogą przechowywać i agregować te dane
w celu późniejszego przesłania. Aby uzyskać więcej informacji,
zapoznaj się z przykładami podanymi w sekcji Agregacja.
Aby aplikacja otrzymała dostęp do usługi, musisz utworzyć i podać atrybut OnFrameListener
w raportach dla poszczególnych klatek. Ten detektor jest wywoływany w każdej klatce, aby zapewnić stały ruch
zapchać dane aplikacjom.
private val jankFrameListener = JankStats.OnFrameListener { frameData ->
// A real app could do something more interesting, like writing the info to local storage and later on report it.
Log.v("JankStatsSample", frameData.toString())
}
Detektor udostępnia informacje o zakłóceniu w przypadku poszczególnych klatek za pomocą funkcji
FrameData. Ten
zawiera następujące informacje o żądanej ramce:
isjank: Flaga wartości logicznej, która wskazuje, czy w ramce wystąpił problem.frameDurationUiNanos: Czas trwania klatki (w nanosekundach).frameStartNanos: Czas rozpoczęcia klatki (w nanosekundach).states: Stan aplikacji w klatce.
Jeśli masz Androida 12 (poziom interfejsu API 31) lub nowszego, możesz użyj tego tagu, aby uzyskać więcej informacji o czasie trwania klatek:
FrameDataApi24zapewniaframeDurationCpuNanosaby wyświetlić czas w obszarach klatki bez procesora graficznego.FrameDataApi31zapewniaframeOverrunNanosaby wyświetlić czas, jaki upłynął od momentu renderowania klatki. gotowe.
Użyj StateInfo w
detektor do przechowywania informacji o stanie aplikacji.
Zwróć uwagę, że funkcja OnFrameListener jest wywoływana w tym samym wątku używanym wewnętrznie do
dostarcza JankStats informacje dotyczące klatek.
W Androidzie w wersji 6 (poziom interfejsu API 23) i starszych jest to wątek główny.
W Androidzie w wersji 7 (poziom interfejsu API 24) i nowszych
utworzony i używany przez FrameMetrics. W obu przypadkach ważne jest, aby
obsługuje wywołania zwrotne i szybko zwraca je, aby uniknąć problemów z wydajnością
w tym wątku.
Pamiętaj też, że obiekt FrameData wysłany w wywołaniu zwrotnym jest ponownie używany w każdym aby uniknąć przydzielania nowych obiektów do raportowania danych. Oznacza to, że musisz skopiować i zapisać je w pamięci podręcznej w innym miejscu, ponieważ obiekt ten powinien być uważane za przestarzałe i przestarzałe, gdy tylko wywołanie zwrotne zostanie zwrócone.
Agreguję
Prawdopodobnie kod aplikacji gromadzi dane poszczególnych klatek,
o zapisywaniu i przesłaniu informacji według własnego uznania. Chociaż szczegóły
dotyczące zapisywania i przesyłania wykraczają poza zakres alfa interfejsu JankStats API.
możesz wyświetlić wstępne działanie związane z agregacją danych dla poszczególnych klatek.
do większej kolekcji przy użyciu usługi JankAggregatorActivity dostępnej w
Repozytorium GitHub.
JankAggregatorActivity
używa klasy JankStatsAggregator do nałożenia własnych raportów
oparty na mechanizmie JankStats OnFrameListener, aby zapewnić
wyższego poziomu abstrakcji w przypadku raportowania tylko zbioru informacji, które
obejmuje wiele klatek.
Zamiast bezpośrednio tworzyć obiekt JankStats, JankAggregatorActivity
tworzy JankStatsAggregator,
który tworzy wewnętrznie własny obiekt JankStats:
class JankAggregatorActivity : AppCompatActivity() {
private lateinit var jankStatsAggregator: JankStatsAggregator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
// Metrics state holder can be retrieved regardless of JankStats initialization.
val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root)
// Initialize JankStats with an aggregator for the current window.
jankStatsAggregator = JankStatsAggregator(window, jankReportListener)
// Add the Activity name as state.
metricsStateHolder.state?.putState("Activity", javaClass.simpleName)
}
Podobny mechanizm jest stosowany w JankAggregatorActivity do wstrzymywania i
wznowić śledzenie, dodając zdarzenie pause() jako sygnał do problemu
raport z wywołaniem issueJankReport(), ponieważ zmiany w cyklu życia
odpowiedni czas na przechwycenie stanu zacięć w aplikacji:
override fun onResume() {
super.onResume()
jankStatsAggregator.jankStats.isTrackingEnabled = true
}
override fun onPause() {
super.onPause()
// Before disabling tracking, issue the report with (optionally) specified reason.
jankStatsAggregator.issueJankReport("Activity paused")
jankStatsAggregator.jankStats.isTrackingEnabled = false
}
Przykładowy kod powyżej to wszystko, czego aplikacja potrzebuje, aby włączyć JankStats i otrzymywać danych ramki.
Zarządzaj stanem
Możesz też chcieć wywołać inne interfejsy API, aby dostosować JankStats. Dla: wstrzykiwanie informacji o stanie aplikacji sprawia, że dane ramek są bardziej przydatne, i dostarcza kontekst dla ramek, w których występuje zacinanie.
Ta statyczna metoda pobiera bieżącą
MetricsStateHolder
dla danej hierarchii widoków.
PerformanceMetricsState.getHolderForHierarchy(view: View): MetricsStateHolder
Można używać dowolnego widoku w aktywnej hierarchii. Ta funkcja sprawdza wewnętrznie,
czy istniejący obiekt Holder jest z nim powiązany.
hierarchię widoków. Informacje te są przechowywane w widoku u góry
w hierarchii. Jeśli taki obiekt nie istnieje, getHolderForHierarchy() tworzy go.
Statyczna metoda getHolderForHierarchy() pozwala uniknąć konieczności zapisywania w pamięci podręcznej.
instancję posiadacza do późniejszego pobrania i ułatwia
istniejącego obiektu stanu z dowolnego miejsca w kodzie (lub nawet kodu biblioteki,
w innym przypadku nie mieliby dostępu do oryginalnej instancji).
Zwróć uwagę, że zwracana wartość jest obiektem posiadacza, a nie samym obiektem stanu. wartość obiektu State w obiekcie jest ustawiana wyłącznie przez JankStats. Ten jeśli aplikacja tworzy obiekt JankStats dla okna zawierającego hierarchię wyświetlania, obiekt stanu zostanie który został utworzony i ustawiony. W przeciwnym razie bez śledzenia informacji statystyki JankStats będą nie jest potrzebny obiekt stanu, nie jest też potrzebny w przypadku aplikacji czy biblioteki, do wstrzykiwania stanu.
Takie podejście umożliwia
pobrać obiekt, który JankStats może następnie uzupełnić. Kod zewnętrzny
może w dowolnym momencie poprosić o podanie jego właściciela. Rozmówcy mogą buforować lekkie urządzenie Holder
i używać go w dowolnym momencie do określenia stanu, w zależności od wartości jego
wewnętrzna właściwość state, jak w przykładowym kodzie poniżej, gdzie stan jest ustawiony tylko
gdy właściwość stanu wewnętrznego posiadacza nie ma wartości null:
val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root)
// ...
metricsStateHolder.state?.putState("Activity", javaClass.simpleName)
Aby kontrolować stan UI lub aplikacji, aplikacja może wprowadzić (lub usunąć) stan
za pomocą metod putState i removeState. JankStats rejestruje sygnaturę czasową
do tych połączeń. Jeśli ramka pokrywa się z czasem rozpoczęcia i zakończenia stanu,
JankStats podaje informacje wraz z danymi o czasie dla
ramki.
W przypadku każdego stanu dodaj 2 informacje: key
(kategorię stanu, np. „RecyclerView”) oraz value (informacje na temat
co działo się w danym momencie, np. „przewijanie”).
Usuń stany za pomocą metody removeState(), gdy ten stan nie jest określony
jest ważny przez dłuższy czas, by zapewnić, że nieprawidłowe lub wprowadzające w błąd informacje nie będą zgłaszane
z danymi klatek.
Wywołanie „putState()” przy użyciu dodanego wcześniej numeru key zastępuje
istniejące value tego stanu z nowym stanem.
Wersja putSingleFrameState() interfejsu stanowego API dodaje stan:
tylko raz – dla kolejnej zgłaszanej klatki. System automatycznie
zostanie wtedy usunięta, aby zapobiec przypadkowemu nieaktualnemu stanowi
kod. Pamiętaj, że nie ma odpowiednika w standardzie singleFrame
removeState(), ponieważ JankStats automatycznie usuwa stany pojedynczej klatki.
private val scrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
// check if JankStats is initialized and skip adding state if not
val metricsState = metricsStateHolder?.state ?: return
when (newState) {
RecyclerView.SCROLL_STATE_DRAGGING -> {
metricsState.putState("RecyclerView", "Dragging")
}
RecyclerView.SCROLL_STATE_SETTLING -> {
metricsState.putState("RecyclerView", "Settling")
}
else -> {
metricsState.removeState("RecyclerView")
}
}
}
}
Pamiętaj, że klucz używany w stanach powinien być na tyle ważny, aby umożliwiać
jego późniejszej analizy. W szczególności, ponieważ stan z taką samą wartością key jak w
zastąpi ona wcześniejszą wartość, spróbuj użyć
unikalne nazwy key obiektów, które mogą mieć różne instancje w
aplikacji lub biblioteki. Na przykład aplikacja z pięcioma różnymi elementami RecyclerView
warto udostępnić możliwe do identyfikacji klucze dla każdego z nich, zamiast używać po prostu
RecyclerView dla każdego z nich, a następnie nie będziesz mieć możliwości łatwego określenia w
danych wynikowych, do których odnoszą się dane ramki.
Heurystyka stymulująca
Aby dostosować wewnętrzny algorytm wykrywania zacinania, użyj funkcji
właściwość jankHeuristicMultiplier.
Domyślnie system definiuje zacinanie jako ramkę, której renderowanie trwa dwa razy dłużej niż bieżącej częstotliwości odświeżania. Nie traktuje szarości jako niczego częstotliwość odświeżania, ponieważ informacje o czasie renderowania aplikacji nie są jasne. Dlatego lepiej jest dodać bufor i zawierać tylko raporty, gdy powodują zauważalne problemy z wydajnością.
Obie te wartości można zmienić w ten sposób odpowiednio do sytuacji lub w celu wymuszenia zacinania, niezbędną do przeprowadzenia testu.
Użycie w Jetpack Compose
Obecnie funkcja JankStats w funkcji Compose nie wymaga konfiguracji.
Aby zachować PerformanceMetricsState podczas wprowadzania zmian w konfiguracji,
zapamiętaj go w taki sposób:
/**
* Retrieve MetricsStateHolder from compose and remember until the current view changes.
*/
@Composable
fun rememberMetricsStateHolder(): PerformanceMetricsState.Holder {
val view = LocalView.current
return remember(view) { PerformanceMetricsState.getHolderForHierarchy(view) }
}
Aby użyć statystyk Jank, dodaj do stateHolder bieżący stan, jak pokazano tutaj:
val metricsStateHolder = rememberMetricsStateHolder()
// Reporting scrolling state from compose should be done from side effect to prevent recomposition.
LaunchedEffect(metricsStateHolder, listState) {
snapshotFlow { listState.isScrollInProgress }.collect { isScrolling ->
if (isScrolling) {
metricsStateHolder.state?.putState("LazyList", "Scrolling")
} else {
metricsStateHolder.state?.removeState("LazyList")
}
}
}
Szczegółowe informacje o używaniu JankStats w aplikacji Jetpack Compose znajdziesz na stronie znajdziesz w naszej przykładowej aplikacji wydajności.
Prześlij opinię
Podziel się z nami swoimi opiniami i pomysłami, korzystając z tych zasobów:
- Narzędzie do śledzenia błędów

- Zgłoś problemy, abyśmy mogli je naprawić. .
Polecane dla Ciebie
- Uwaga: tekst linku wyświetla się, gdy JavaScript jest wyłączony
- Utwórz profile Baseline {:#Creation-profile-rules}
- Argumenty instrumentacji mikrotestów
- Argumenty instrumentacji w ramach analizy porównawczej