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

相关推荐
Jiaberrr1 天前
uniapp 安卓 APP 后台持续运行(保活)的尝试办法
android·前端·javascript·uni-app·app·保活
iOS阿玮1 天前
社交的本质是价值交换,请不要浪费别人的时间。
uni-app·app·apple
Xy9101 天前
AppTrace技术全景:开发者视角下的工具链与实践经验
app
iOS阿玮2 天前
苹果2024透明报告看似更加严格的背后是利好!
uni-app·app·apple
yxc_inspire2 天前
基于Qt的app开发第十三天
c++·qt·app·tcp·面向对象
iOS阿玮3 天前
苹果审核被拒4.1-Copycats过审技巧实操
uni-app·app·apple
宋智孝的小迷弟4 天前
Android 异步数据流:Kotlin Flow 为何成为新一代“利器”?LiveData 又有何局限?
android·面试·app
活哈哈哈哈4 天前
安卓AppWidget桌面小组件在国产移动设备的一些适配问题
app
iOS阿玮4 天前
不想被苹果卡审最好错开这两个提审时间
uni-app·app·apple
夜路未染4 天前
Android组件之Activity知识点梳理
app