
页面异常率反映了页面渲染过程中出现异常的概率,计算公式为:页面异常率 = 异常发生次数 / 整体页面PV数。
异常发生次数统计
通过全局变量 exceptionCount 在异常捕获回调中累加异常次数:
int exceptionCount = 0;
Future<Null> _reportError(dynamic error, dynamic stackTrace) async {
exceptionCount++; //累加异常次数
FlutterCrashPlugin.postException(error, stackTrace);
}整体页面PV数统计
通过 NavigatorObserver 监听页面打开行为,累加PV数:
int totalPV = 0;
class MyObserver extends NavigatorObserver{
@override
void didPush(Route route, Route previousRoute) {
super.didPush(route, previousRoute);
totalPV++; //累加PV
}
}计算页面异常率
double pageException() {
if(totalPV == 0) return 0;
return exceptionCount/totalPV;
}FPS反映页面渲染流畅度,推荐值为60Hz。计算需结合VSync信号周期(16.67毫秒)。
帧绘制时间采集
注册 window.onReportTimings 回调,保留最近25帧数据:
const maxframes = 25;
final lastFrames = List<FrameTiming>();
const frameInterval = Duration(microseconds: Duration.microsecondsPerSecond ~/ 60);
void onReportTimings(List<FrameTiming> timings) {
lastFrames.addAll(timings);
if(lastFrames.length > maxframes) {
lastFrames.removeRange(0, lastFrames.length - maxframes);
}
}FPS计算公式
其中理论应渲染帧数为每帧耗时除以VSync周期后向上取整的总和。
实现代码
double get fps {
int sum = 0;
for (FrameTiming timing in lastFrames) {
int duration = timing.timestampInMicroseconds(FramePhase.rasterFinish) -
timing.timestampInMicroseconds(FramePhase.buildStart);
sum += (duration / frameInterval.inMicroseconds).ceil();
}
return lastFrames.isEmpty ? 60 : 60 * lastFrames.length / sum;
}页面加载时长反映从页面触发渲染到首帧完成的时间,可通过以下方式采集:
关键时间点记录
WidgetsBinding 的首次帧回调中记录结束时间。代码实现
DateTime _pageStartTime;
void _startPageLoad() {
_pageStartTime = DateTime.now();
}
void _endPageLoad() {
final loadTime = DateTime.now().difference(_pageStartTime).inMilliseconds;
debugPrint('Page load time: $loadTime ms');
}
// 在页面初始化时调用_startPageLoad
// 在首帧回调中调用_endPageLoad
WidgetsBinding.instance.addPostFrameCallback((_) {
_endPageLoad();
});优化建议
Future 链式追踪总耗时。