【笔记】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

相关推荐
百锦再5 天前
Android Studio中OpenCV应用详解:图像处理、颜色对比与OCR识别
android·java·图像处理·opencv·kotlin·app·android studio
百锦再9 天前
Android Studio开发中Application和Activity生命周期详解
android·java·ide·app·gradle·android studio·studio
移动开发者1号10 天前
Android现代进度条替代方案
android·app
iOS阿玮10 天前
重要通知!使用Pingpong收款的开发者请注意查收!
app·apple
长点点11 天前
从架构角度了解安卓APP(1):安卓核心组件的设计逻辑与演进
android·架构·app
QING61813 天前
AndroidManifest.xml中application标签属性详解 —— 新手指南
android·app·trae
百锦再13 天前
Java与Kotlin在Android开发中的全面对比分析
android·java·google·kotlin·app·效率·趋势
CYRUS STUDIO13 天前
Android APP 热修复原理
android·app·frida·hotfix·热修复
CYRUS_STUDIO14 天前
Android APP 热修复原理
android·app·hotfix
iOS阿玮14 天前
别等了,今天是Xcode15时代的最后一天。
前端·app·apple