Mithilfe der JankStats-Bibliothek können Sie Leistungsprobleme in Anwendungen. Der Begriff Jank bezieht sich auf Anwendungsframes, deren Rendering zu lange dauert. und die JankStats-Bibliothek bietet Berichte zu den Verzögerungsstatistiken Ihrer App.
Rechte
JankStats baut auf den vorhandenen Funktionen der Android-Plattform auf, darunter: FrameMetrics API unter Android 7 (API-Level 24) und höher oder OnPreDrawListener Versionen. Diese Mechanismen können Anwendungen dabei helfen zu verfolgen, wie lange Frames abgeschlossen ist. Die JanksStats-Bibliothek bietet zwei zusätzliche Funktionen, dynamischer und einfacher zu nutzen: Verzögerungen und UI-Status.
Jank-Heuristik
Sie können FrameMetrics zwar verwenden, um die Frame-Dauer zu verfolgen, aber FrameMetrics Unterstützung bei der Ermittlung der tatsächlichen Verzögerung bieten. JankStats hat jedoch konfigurierbaren internen Mechanismen, um zu ermitteln, wann Verzögerungen auftreten. sofort nützlicher machen.
UI-Status
Häufig ist es wichtig, den Kontext von Leistungsproblemen in deiner App zu kennen. Wenn Sie beispielsweise eine komplexe Multiscreen-App entwickeln, die FrameMetrics verwendet, und feststellen, dass die Frames in Ihrer App häufig extrem stockend sind, diese Informationen in einen Kontext zu setzen, indem er weiß, wo das Problem aufgetreten ist, was die Nutzenden tun und wie sie reproduziert werden können.
JankStats löst dieses Problem durch die Einführung einer state
-API, mit der Sie
mit der Bibliothek kommunizieren, um Informationen zu den App-Aktivitäten bereitzustellen. Wann?
JankStats protokolliert Informationen über einen fehlerhaften Frame und enthält den aktuellen Status
die Anwendung in Verzögerungsberichten.
Nutzung
Um mit JankStats zu arbeiten, müssen Sie die Bibliothek für jedes einzelne Element instanziieren und aktivieren.
Window
Jedes JankStats-Objekt erfasst Daten.
nur innerhalb eines Window
. Zum Instanziieren der Bibliothek ist eine Window
-Instanz erforderlich
zusammen mit OnFrameListener
Listener. Mit beiden werden Messwerte an den Client gesendet. Der Listener wird mit
FrameData
in jedem Frame
und folgende Details:
- Beginn des Frames
- Werte für die Dauer
- Gibt an, ob der Frame als Verzögerung betrachtet werden soll
- Eine Reihe von String-Paaren, die Informationen zum Anwendungsstatus enthalten im Frame
Um JankStats nützlicher zu machen, sollten Anwendungen die Bibliothek mit
relevante Informationen zum Status der Benutzeroberfläche für die Berichterstellung in FrameData. Sie schaffen das
über die
PerformanceMetricsState
API (nicht direkt JankStats), bei der die gesamte Statusverwaltungslogik und APIs
.
Initialisierung
Um die JankStats-Bibliothek zu verwenden, fügen Sie zuerst die JankStats-Abhängigkeit zu Ihrem Gradle-Datei:
implementation "androidx.metrics:metrics-performance:1.0.0-beta01"
Initialisieren und aktivieren Sie anschließend JankStats für jedes Window
. Außerdem sollten Sie
JankStats-Tracking, wenn eine Aktivität in den Hintergrund geht Erstellen und aktivieren
JankStats-Objekt in Ihren Activity-Überschreibungen:
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)
// ...
}
Im obigen Beispiel werden Statusinformationen zur aktuellen Aktivität, nachdem das JankStats-Objekt erstellt wurde. Alle zukünftigen FrameData-Berichte die für dieses JankStats-Objekt erstellt wurden, enthalten jetzt auch Aktivitätsdaten.
Die Methode JankStats.createAndTrack
verweist auf eine Window
.
-Objekt, das ein Proxy für die View-Hierarchie innerhalb dieses Window
-Elements ist, sowie
für Window
selbst. jankFrameListener
wird im gleichen verwendeten Thread aufgerufen
diese Informationen von der Plattform
intern an JankStats weiterleiten.
Um Tracking und Berichterstellung für
ein JankStats-Objekt zu aktivieren,
isTrackingEnabled = true
anrufen. Es ist zwar standardmäßig aktiviert,
Durch das Pausieren einer Aktivität wird das Tracking deaktiviert. Aktivieren Sie in diesem Fall die
bevor Sie fortfahren. Wenn Sie das Tracking beenden möchten, rufen Sie isTrackingEnabled = false
auf.
override fun onResume() {
super.onResume()
jankStats.isTrackingEnabled = true
}
override fun onPause() {
super.onPause()
jankStats.isTrackingEnabled = false
}
Berichte
Die JankStats-Bibliothek dokumentiert das gesamte Daten-Tracking für jeden Frame an den
OnFrameListener
für aktivierte JankStats-Objekte. Apps können Daten speichern und zusammenfassen
um Daten zu einem späteren Zeitpunkt hochzuladen. Weitere Informationen finden Sie in
Sehen Sie sich die Beispiele im Abschnitt Aggregation an.
Du musst die OnFrameListener
erstellen und bereitstellen, damit deine App
die Berichte zu den einzelnen Frames. Dieser Listener wird auf jedem Frame aufgerufen, um
in Apps verschieben.
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())
}
Der Listener gibt pro Frame Informationen zu Verzögerungen mit der Methode
FrameData
-Objekt. Dieses
enthält die folgenden Informationen über den angeforderten Frame:
isjank
: Boolescher Parameter, der angibt, ob im Frame eine Verzögerung aufgetreten ist.frameDurationUiNanos
: Frame-Dauer (in Nanosekunden).frameStartNanos
: Startzeit des Frames (in Nanosekunden).states
: Status der App während des Frames.
Wenn du Android 12 (API-Level 31) oder höher verwendest, kannst du Verwenden Sie folgenden Code, um mehr Daten zur Framedauer bereitzustellen:
FrameDataApi24
bietetframeDurationCpuNanos
um die in den Nicht-GPU-Bereichen des Frames verbrachte Zeit anzuzeigen.FrameDataApi31
bietetframeOverrunNanos
um die Zeit anzuzeigen, die der Frame nach Ablauf der Frame-Frist benötigt hat. abgeschlossen ist.
Verwenden Sie StateInfo
in der
Listener zum Speichern von Informationen zum Anwendungsstatus.
Beachten Sie, dass OnFrameListener
in demselben Thread aufgerufen wird, der intern verwendet wird, um
die Informationen pro Frame an JankStats senden.
Bei Android-Version 6 (API-Level 23) und niedriger ist dies der Hauptthread (UI-Thread).
Unter Android Version 7 (API-Level 24) und höher ist es die
-Thread, der für FrameMetrics erstellt und verwendet wird. In beiden Fällen ist es wichtig,
den Callback verarbeiten und schnell zurückkehren, um Leistungsprobleme auf
zu diesem Thread.
Beachten Sie außerdem, dass das im Rückruf gesendete FrameData-Objekt bei jedem um zu verhindern, dass neue Objekte für die Berichterstellung zugewiesen werden müssen. Das bedeutet, dass Sie diese Daten kopieren und an anderer Stelle im Cache speichern müssen, da dieses Objekt wird als „statle“ und „veraltet“ betrachtet, sobald der Callback zurückgegeben wird.
Aggregieren
Sie möchten wahrscheinlich, dass Ihr App-Code die Daten pro Frame aggregiert, sodass
Sie können die Informationen nach eigenem Ermessen speichern und hochladen. Obwohl Details
zum Speichern und Hochladen von Daten werden nicht im Umfang der Alpha JankStats API behandelt.
können Sie eine vorläufige Aktivität
zum Aggregieren von Daten pro Frame
in einer größeren Sammlung mit JankAggregatorActivity
in unserer
GitHub-Repository.
JankAggregatorActivity
verwendet die JankStatsAggregator
-Klasse, um eigene Berichte übereinanderzulegen
neben dem OnFrameListener
-Mechanismus von JankStats zur Bereitstellung einer
einer übergeordneten Abstraktionsebene,
um nur eine Sammlung von Informationen
mehrere Frames umfasst.
Anstatt ein JankStats-Objekt direkt zu erstellen, JankAggregatorActivity
Erstellt einen JankStatsAggregator.
, das intern ein eigenes JankStats-Objekt erstellt:
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)
}
In JankAggregatorActivity
wird ein ähnlicher Mechanismus zum Pausieren und
Fortsetzen des Trackings, wobei das Ereignis pause()
als Signal für das Problem hinzugefügt wird
einen Bericht mit einem Aufruf von issueJankReport()
, da Änderungen des Lebenszyklus
Zeit, um den Status der Verzögerung in der Anwendung zu erfassen:
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
}
Der obige Beispielcode ist alles, was eine App benötigt, um JankStats zu aktivieren und Frame-Daten.
Status verwalten
Es ist möglich, dass Sie andere APIs aufrufen möchten, um JankStats anzupassen. Für werden Frame-Daten durch das Einfügen von App-Status-Informationen hilfreicher, und bietet Kontext für die Frames, in denen Verzögerungen auftreten.
Diese statische Methode ruft den aktuellen
MetricsStateHolder
für eine bestimmte View-Hierarchie.
PerformanceMetricsState.getHolderForHierarchy(view: View): MetricsStateHolder
Jede Ansicht in einer aktiven Hierarchie kann verwendet werden. Intern wird überprüft, ob
ob ein vorhandenes Holder
-Objekt mit diesem verknüpft ist
Hierarchieansicht. Diese Informationen werden in einer Ansicht oben im Cache gespeichert.
Hierarchie. Falls kein solches Objekt vorhanden ist, erstellt getHolderForHierarchy()
eines.
Mit der statischen Methode getHolderForHierarchy()
müssen Sie nicht zwischen
Holder-Instanz an einen anderen Ort für den späteren Abruf zu verschieben. Dies vereinfacht das Abrufen
ein vorhandenes Zustandsobjekt an einer beliebigen Stelle im Code (oder sogar Bibliothekscode, der
sonst keinen Zugriff auf die ursprüngliche Instanz hätten.)
Beachten Sie, dass der Rückgabewert ein Halteobjekt ist, nicht das Statusobjekt selbst. Die -Wert des state-Objekts innerhalb des Halters wird nur von JankStats festgelegt. Das Wenn eine Anwendung ein JankStats-Objekt für das Fenster erstellt, das diese ist das Zustandsobjekt festgelegt und festgelegt wurden. Ohne dass JankStats die Informationen erfasst, ist weder das "state"-Objekt noch eine App oder Bibliothek um den Zustand einzufügen.
Dieser Ansatz ermöglicht es,
einen Halter abzurufen, den JankStats anschließend füllen kann. Externer Code
jederzeit nach dem Inhaber fragen kann. Aufrufer können die einfache Holder
-Datei im Cache speichern
-Objekt und können es jederzeit zum Festlegen des Status verwenden, je nach dem Wert seines
Internes state
-Attribut wie im Beispielcode unten, bei dem nur der Status
Die interne Statuseigenschaft des Inhabers ist nicht null:
val metricsStateHolder = PerformanceMetricsState.getHolderForHierarchy(binding.root)
// ...
metricsStateHolder.state?.putState("Activity", javaClass.simpleName)
Zur Steuerung des UI-/App-Status kann eine App einen Status einfügen (oder entfernen)
mit den Methoden putState
und removeState
. JankStats protokolliert den Zeitstempel für
diesen Anrufen. Wenn sich ein Frame mit der Start- und Endzeit des Status überschneidet,
JankStats liefert diese Informationen zusammen mit den Zeitdaten für die
Frame.
Fügen Sie für jeden Bundesstaat zwei Informationen hinzu: key
(eine Zustandskategorie, z. B. "RecyclerView") und value
(Informationen über
was zu dieser Zeit geschah, z. B. „Scrollen“.
Entfernen Sie Status mithilfe der Methode removeState()
, wenn dieser Status nicht vorhanden ist
um sicherzustellen, dass keine falschen oder irreführenden Informationen gemeldet werden.
mit Frame-Daten.
Wenn putState()
mit einer zuvor hinzugefügten key
aufgerufen wird, ersetzt dies das
value
dieses Bundesstaates durch den neuen Bundesstaat ersetzt.
Die putSingleFrameState()
-Version der State API fügt einen Status hinzu, der
wird nur einmal
beim nächsten gemeldeten Frame protokolliert. Das System hat automatisch
und entfernt es anschließend wieder. So vermeiden Sie,
Ihren Code. Es gibt kein SingleFrame-Äquivalent zu
removeState()
, da JankStats die Zustände einzelner Frames automatisch entfernt.
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")
}
}
}
}
Beachten Sie, dass der Schlüssel für Statusangaben so aussagekräftig sein muss, dass er
spätere Analyse. Da ein Bundesstaat mit derselben key
wie ein Bundesstaat,
den vorherigen Wert ersetzt, sollten Sie versuchen,
eindeutige key
-Namen für Objekte, die unterschiedliche Instanzen in Ihrem
App oder Bibliothek aus. Eine App mit fünf verschiedenen RecyclerViews
eindeutige Schlüssel für jeden Schlüssel bereitstellen, anstatt einfach nur
RecyclerView
für jeden einzelnen Wert und kann dann im
auf welche Instanz sich die Frame-Daten beziehen.
Jank-Heuristik
Um den internen Algorithmus zur Bestimmung, was als Verzögerung betrachtet wird, anzupassen, verwenden Sie
Das Attribut jankHeuristicMultiplier
Standardmäßig definiert das System Verzögerung als einen Frame, dessen Rendering doppelt so lang dauert wie die aktuelle Aktualisierungsrate. Verzögerung wird nicht als etwas über da die Informationen zur Renderingzeit der App nicht löschen. Daher ist es besser, einen Puffer hinzuzufügen und nur wenn sie spürbare Leistungsprobleme verursachen.
Beide Werte können mit diesen Methoden an die Situation angepasst werden. der App genauer an. Sie können auch testen, ob Verzögerungen auftreten oder nicht. die für den Test erforderlich sind.
Verwendung in Jetpack Compose
Derzeit ist nur sehr wenig Einrichtung erforderlich, um JankStats in Compose zu verwenden.
Um die PerformanceMetricsState
bei Konfigurationsänderungen beizubehalten,
sich das so zu merken:
/**
* 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) }
}
Um JankStats zu verwenden, fügen Sie den aktuellen Status zu stateHolder
hinzu, wie hier gezeigt:
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")
}
}
}
Ausführliche Informationen zur Verwendung von JankStats in Ihrer Jetpack Compose-Anwendung finden Sie unter finden Sie in unserer Beispiel-App zur Leistungssteigerung.
Feedback geben
Wir freuen uns über dein Feedback und deine Ideen:
- Problemverfolgung
- Melde Probleme, damit wir sie beheben können.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Baseline-Profile erstellen {:#creating-profile-rules}
- Argumente zur MikroBenchmark-Instrumentierung
- Makros zur Instrumentierungsargumente