-
Notifications
You must be signed in to change notification settings - Fork 209
/
JankStatsAggregator.kt
103 lines (93 loc) · 4.17 KB
/
JankStatsAggregator.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.jankstats
import android.view.Window
import androidx.metrics.performance.FrameData
import androidx.metrics.performance.JankStats
/**
* This utility class can be used to provide a simple data aggregation mechanism for JankStats.
* Instead of receiving a callback on every frame and caching that data, JankStats users can
* create JankStats indirectly through this Aggregator class, which will compile the data
* and issue it upon request.
*
* @param window The Window for which stats will be tracked. A JankStatsAggregator
* instance is specific to each window in an application, since the timing metrics are
* tracked on a per-window basis internally.
* @param onJankReportListener This listener will be called whenever there is a call to
* [issueJankReport].
* @throws IllegalStateException This function will throw an exception if `window` has
* a null DecorView.
*/
class JankStatsAggregator(
window: Window,
private val onJankReportListener: OnJankReportListener
) {
private val listener = JankStats.OnFrameListener { frameData ->
++numFrames
if (frameData.isJank) {
jankReport.add(frameData.copy())
if (jankReport.size >= REPORT_BUFFER_LIMIT) {
issueJankReport("Max buffer size reached")
}
}
}
val jankStats = JankStats.createAndTrack(window, listener)
private var jankReport = ArrayList<FrameData>()
private var numFrames: Int = 0
/**
* Issue a report on current jank data. The data includes FrameData for every frame
* experiencing jank since the listener was set, or since the last time a report
* was issued for this JankStats object. Calling this function will cause the jankData
* to be reset and cleared. Note that this function may be called externally, from application
* code, but it may also be called internally for various reasons (to reduce memory size
* by clearing the buffer, or because there was an important lifecycle event). The
* [reason] parameter explains why the report was issued if it was not called externally.
*
* @param reason An optional parameter specifying the reason that the report was issued.
* This parameter may be used if JankStats issues a report for some internal reason.
*/
fun issueJankReport(reason: String = "") {
val jankReportCopy = jankReport
val numFramesCopy = numFrames
onJankReportListener.onJankReport(reason, numFramesCopy, jankReportCopy)
jankReport = ArrayList()
numFrames = 0
}
/**
* This listener is called whenever there is a call to [issueJankReport].
*/
fun interface OnJankReportListener {
/**
* The implementation of this method will be called whenever there is a call
* to [issueJankReport].
*
* @param reason Optional reason that this report was issued
* @param totalFrames The total number of frames (jank and not) since collection
* began (or since the last time the report was issued and reset)
* @param jankFrameData The FrameData for every frame experiencing jank during
* the collection period
*/
fun onJankReport(reason: String, totalFrames: Int, jankFrameData: List<FrameData>)
}
companion object {
/**
* The number of frames for which data can be accumulated is limited to avoid
* memory problems. When the limit is reached, a report is automatically issued
* and the buffer is cleared.
*/
private const val REPORT_BUFFER_LIMIT = 1000
}
}