【笔记】Android 耗时统计

概述

对于 Android 的耗时统计,在 Android 7.0, 增加了一个 Api 可以方便的统计一个 Window 的 View 树的绘制耗时。低于 API 26 可以使用 Choreographer 监听帧时间。

OnFrameMetricsAvailableListener 介绍

OnFrameMetricsAvailableListener 是 Android 提供的一个监听器接口,用于监测应用 UI 帧的性能指标,可以帮助开发者分析应用的流畅性和性能问题。


1. 作用

  • 监听 FrameMetrics 数据,分析 每一帧 的性能信息。
  • 获取 渲染时间、绘制时间、输入延迟 等关键指标。
  • 帮助优化 掉帧、卡顿(Jank) 问题。

2. 适用场景

  • 监测 UI 性能 ,发现 卡顿(Jank)
  • 优化流畅度 ,减少 丢帧长帧(> 16ms)。
  • 调试复杂 UI 组件 ,分析 动画流畅性

3. 基本用法

3.1 注册监听器

要使用 OnFrameMetricsAvailableListener,可以通过 Window 注册监听:

java 复制代码
import android.app.Activity;
import android.view.FrameMetrics;
import android.view.Window;
import android.view.Window.OnFrameMetricsAvailableListener;
import android.os.Handler;
import android.os.Looper;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 获取 Window 对象
        Window window = getWindow();

        // 注册监听器
        window.addOnFrameMetricsAvailableListener(new OnFrameMetricsAvailableListener() {
            @Override
            public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation) {
                // 获取 Vsync 信号到帧完成的总时间(纳秒)
                long totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
                long totalMs = totalDuration / 1_000_000; // 转换为毫秒

                // 输出帧渲染时间
                System.out.println("Frame Time: " + totalMs + " ms");
            }
        }, new Handler(Looper.getMainLooper())); // 在主线程执行
    }
}

4. 关键指标

FrameMetrics 提供了多个关键帧性能指标,使用 getMetric(int id) 获取:

指标名称 说明
FrameMetrics.TOTAL_DURATION 整帧渲染时间,从 Vsync 到帧完成的时间
FrameMetrics.INPUT_HANDLING_DURATION 输入事件处理时间(用户触摸后到开始处理时间)
FrameMetrics.ANIMATION_DURATION 动画执行时间
FrameMetrics.LAYOUT_MEASURE_DURATION 测量 & 布局时间
FrameMetrics.DRAW_DURATION 绘制时间
FrameMetrics.SYNC_DURATION 同步事务时间(View 刷新所需的 GPU 处理时间)
FrameMetrics.COMMAND_ISSUE_DURATION CPU 端提交时间(将命令发送到 GPU 的时间)
FrameMetrics.SWAP_BUFFERS_DURATION Swap Buffers 时间(显示到屏幕所需时间)
FrameMetrics.GPU_COMPLETION_DURATION GPU 渲染时间
FrameMetrics.UNKNOWN_DELAY_DURATION 未知延迟时间(其他未知影响)

5. 计算掉帧情况

如果 TOTAL_DURATION 超过 16ms (60FPS),说明该帧 丢帧,可以计算掉帧数:

ini 复制代码
java
复制编辑
int frameTimeMs = (int) (frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION) / 1_000_000);
int droppedFrames = frameTimeMs / 16; // 超过 16ms 计算掉帧数
if (droppedFrames > 0) {
    System.out.println("Dropped Frames: " + droppedFrames);
}

6. 移除监听器

如果不再需要监听,可以移除:

ini 复制代码
java
复制编辑
window.removeOnFrameMetricsAvailableListener(listener);

7. 适用 Android 版本

  • OnFrameMetricsAvailableListener 需要 API 26(Android 8.0)及以上
  • 低于 API 26 可以使用 Choreographer 监听帧时间。

实践优化

  • 如果 INPUT_HANDLING_DURATION 高,说明 输入事件处理 慢,优化 onTouchEvent()dispatchTouchEvent()
  • 如果 LAYOUT_MEASURE_DURATION 高,优化 View.measure()View.layout(),减少不必要的 requestLayout()
  • 如果 DRAW_DURATION 高,减少 onDraw() 复杂度,使用 ViewStubRecyclerView 复用视图。
  • 如果 GPU_COMPLETION_DURATION 高,优化 GPU 负担,如减少 Overdraw阴影效果

Choreographer 低版本介绍

Choreographer 是 Android 提供的 帧回调机制 ,用于 监听 UI 线程的绘制周期 ,可以在低版本(API 16+)上实现 帧率监测性能分析


1. 作用

  • 监测 UI 渲染 :提供 VSync 信号 触发的 回调 ,用于监听 每一帧的绘制情况
  • 计算丢帧情况 :可以检测 帧率(FPS) ,发现 卡顿(Jank)
  • 优化 UI 性能 :可用于 定时动画减少不必要的重绘

2. 适用场景

  • Android 4.1(API 16)及以上 设备 (比 OnFrameMetricsAvailableListener 兼容性更好)
  • 性能监测:统计帧率、掉帧
  • 动画优化:精确控制动画帧同步

3. 使用示例

3.1 监听帧回调

使用 Choreographer 监听 每一帧的绘制周期

java 复制代码
import android.os.Handler;
import android.os.Looper;
import android.view.Choreographer;

public class FPSMonitor implements Choreographer.FrameCallback {
    private long lastFrameTimeNanos = 0;
    private int frameCount = 0;

    public void start() {
        Choreographer.getInstance().postFrameCallback(this); // 开始监听
    }

    @Override
    public void doFrame(long frameTimeNanos) {
        if (lastFrameTimeNanos > 0) {
            // 计算当前帧间隔(单位:毫秒)
            long frameIntervalMs = (frameTimeNanos - lastFrameTimeNanos) / 1_000_000;
            System.out.println("Frame Time: " + frameIntervalMs + " ms");

            // 检查掉帧情况
            if (frameIntervalMs > 16) { // 16ms 代表 60FPS,超过表示丢帧
                int droppedFrames = (int) (frameIntervalMs / 16);
                System.out.println("Dropped Frames: " + droppedFrames);
            }
        }

        lastFrameTimeNanos = frameTimeNanos;
        frameCount++;

        // 继续监听下一帧
        Choreographer.getInstance().postFrameCallback(this);
    }

    public void stop() {
        Choreographer.getInstance().removeFrameCallback(this); // 停止监听
    }
}

3.2 在 Activity 里使用

typescript 复制代码
FPSMonitor fpsMonitor;

@Override
protected void onResume() {
    super.onResume();
    fpsMonitor = new FPSMonitor();
    fpsMonitor.start(); // 开启 FPS 监测
}

@Override
protected void onPause() {
    super.onPause();
    fpsMonitor.stop(); // 停止 FPS 监测
}

4. 计算 FPS(帧率)

Choreographer 回调中,每秒计算一次 FPS:

java 复制代码
private int frameCount = 0;
private long startTime = System.currentTimeMillis();

@Override
public void doFrame(long frameTimeNanos) {
    frameCount++;

    long currentTime = System.currentTimeMillis();
    if (currentTime - startTime >= 1000) { // 每秒计算一次 FPS
        int fps = frameCount;
        System.out.println("FPS: " + fps);
        frameCount = 0;
        startTime = currentTime;
    }

    // 继续监听下一帧
    Choreographer.getInstance().postFrameCallback(this);
}

如果 FPS 低于 60,说明可能存在掉帧现象。


5. Choreographer VS Handler.postDelayed()

对比项 Choreographer Handler.postDelayed()
适用 API 版本 API 16+ API 1+
帧同步机制 VSync 信号(与 UI 线程同步) 仅基于时间间隔(不一定与帧同步)
适用于 性能监测、动画同步 定时任务(与 UI 刷新无关)

如果需要 精准控制 UI 刷新(如帧率监测)Choreographer Handler.postDelayed() 更精准


6. 实践优化

  • 如果 frameIntervalMs > 16ms,说明 UI 丢帧
  • 减少 onDraw() 中的复杂计算
  • 避免 UI 线程的 阻塞任务(如 I/O 操作)
  • 使用 RecyclerView 代替 ListView 进行高效列表滚动
  • 优化 动画,减少不必要的 invalidate()

7. 适用 Android 版本

Choreographer 适用于 Android 4.1+(API 16+)

OnFrameMetricsAvailableListener 兼容性更好

适用于 FPS 监测、掉帧分析、动画优化

如果你的项目支持 Android 8.0+(API 26+) ,可以使用 OnFrameMetricsAvailableListener,否则 Choreographer 是更好的选择

总结

OnFrameMetricsAvailableListener 是监控 Android UI 性能的工具

✅ 能 获取每一帧的详细信息 ,帮助开发者发现卡顿问题

适用于 UI 调优 ,优化 丢帧、动画流畅度

✅ 适用于 Android 8.0+(API 26) ,低版本可以使用 Choreographer

相关推荐
私人珍藏库13 小时前
[Android] zip解压缩管理-全格式压缩包一键解压+打包
android·app·生活·工具·多功能
Fansi4 天前
iOS 实时活动(Live Activity)开发指南
app
duanze4 天前
从零开始Android商业项目Vibe coding完全指南(八)
app·vibecoding
Bigger9 天前
Tauri (26)——托盘图标总对不上系统主题?一行 Template Image 搞定
前端·rust·app
duanze14 天前
从零开始Android商业项目Vibe coding完全指南(七)
app·vibecoding
方白羽19 天前
一份 AGENTS.md,让 Android AI 代码规范率飙升
android·app·客户端
私人珍藏库19 天前
[Android] OldRoll复古胶片相机高级版-徕卡-哈苏-宝丽来等等
数码相机·智能手机·app·工具·软件·多功能
私人珍藏库19 天前
[Android] 红妆相机-拍照美颜图片美化工具
android·数码相机·app·软件·多功能
私人珍藏库20 天前
[Android] 精图地球-高清卫星3D街景VR地图工具
智能手机·app·工具·软件·多功能
私人珍藏库20 天前
[Android] 视频下载鸟 v20.02 会员
android·人工智能·智能手机·app·工具·多功能