• 作者:老汪软件技巧
  • 发表时间:2024-10-30 11:02
  • 浏览量:

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

在 Android 开发中,监控应用的帧率(FPS)是评估应用性能和发现卡顿问题的一个重要指标。本次介绍一些常用的方法来监控 Android 应用的 FPS,包括如何实现这些方法的详细说明和代码示例。

使用 Choreographer API

从 Android 4.1(API 16)开始,Choreographer API 能够帮助开发者在每一帧进行操作,适合用于 FPS 的监控。

判断掉帧和卡顿

在使用 Choreographer API 中,可以通过以下方式判断掉帧或卡顿:

1、 计算帧间隔时间:

2、 设置阈值:

实现方案与代码创建一个类,使用 Choreographer.FrameCallback 接口来实现帧率监控。

import android.os.Build;
import android.os.Looper;
import android.util.Log;
import android.view.Choreographer;
public class FPSMonitor implements Choreographer.FrameCallback {
    private static final String TAG = "FrameMonitor";
    private static final long FRAME_INTERVAL_NANOS = 16666666; // 16.6ms in nanoseconds (roughly 60 FPS)
    private long lastFrameTimeNanos = 0;
    public void start() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            Choreographer.getInstance().postFrameCallback(this);
        } else {
            // 对于低于 API 16 的设备需要实现兼容方案
            Log.e(TAG, "Device does not support Choreographer API");
        }
    }
    @Override
    public void doFrame(long frameTimeNanos) {
        if (lastFrameTimeNanos == 0) {
            lastFrameTimeNanos = frameTimeNanos;
        } else {
            long elapsedNanos = frameTimeNanos - lastFrameTimeNanos;
            if (elapsedNanos > FRAME_INTERVAL_NANOS) {
                long droppedFrames = elapsedNanos / FRAME_INTERVAL_NANOS;
                Log.w(TAG, "Dropped frames: " + droppedFrames);
                // 检测到掉帧,打印当前线程的堆栈信息
                Thread currentThread = Thread.currentThread();
                StackTraceElement[] stackTraceElements = currentThread.getStackTrace();
                StringBuilder stackTrace = new StringBuilder("Stack trace:\n");
                for (StackTraceElement element : stackTraceElements) {
                    stackTrace.append("\tat ").append(element.toString()).append("\n");
                }
                Log.i(TAG, stackTrace.toString());
            }
            lastFrameTimeNanos = frameTimeNanos;
        }
        // Schedule the next frame callback
        Choreographer.getInstance().postFrameCallback(this);
    }
}

在你的应用中启动 FPS 监控。

public class MainActivity extends AppCompatActivity {
    private FPSMonitor fpsMonitor;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fpsMonitor = new FPSMonitor();
        fpsMonitor.start();
    }
}

使用 FrameMetrics API 进行掉帧检测

监控单画面卡顿_监控器卡顿_

在 Android 7.0(API 24)及更高版本中,你可以使用 FrameMetrics API 来监控应用的帧率和掉帧情况。FrameMetrics 提供了一种强大的方法来衡量和分析视图的绘制性能。

以下是使用 FrameMetrics API 进行掉帧检测的详细介绍和代码示例:

1、 确保设备支持:仅在 API 24 及更高版本上可用,因此需要进行版本检查。

2、 注册 FrameMetrics Listener:

我们需要使用 Window 对象来注册一个 OnFrameMetricsAvailableListener,这个监听器会在每一帧结束时提供 FrameMetrics 数据。

示例代码

以下是一个简单的示例,展示如何使用 FrameMetrics API 进行掉帧检测并打印相关信息:

import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.FrameMetrics;
import android.view.Window;
import android.view.Window.OnFrameMetricsAvailableListener;
public class FrameMetricsActivity extends Activity {
    private static final String TAG = "FrameMetricsActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            getWindow().addOnFrameMetricsAvailableListener(new OnFrameMetricsAvailableListener() {
                @Override
                public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation) {
                    long totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
                    long intendedDuration = frameMetrics.getMetric(FrameMetrics.INTENDED_VSYNC_TIMESTAMP) 
                            - frameMetrics.getMetric(FrameMetrics.FRAME_PRESENT_TIMESTAMP);
                    
                    // 拿到掉的帧数量
                    Log.d(TAG, "Dropped frames since last: " + dropCountSinceLastInvocation);
                    
                    if (totalDuration > intendedDuration) {
                        Log.w(TAG, "Frame duration exceeded: " + totalDuration);
                        
                        // 当检测到掉帧时打印堆栈信息
                        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
                        StringBuilder stackTrace = new StringBuilder("Stack trace:\n");
                        for (StackTraceElement element : stackTraceElements) {
                            stackTrace.append("\tat ").append(element.toString()).append("\n");
                        }
                        Log.i(TAG, stackTrace.toString());
                    }
                }
            }, null);
        } else {
            Log.e(TAG, "FrameMetrics API not available on this device");
        }
    }
}

代码说明注意事项其他可行方案

SurfaceView 的 FPS 监控:

OpenGL 的 FPS 监控:

第三方工具:

TraceView 和 systrace: