欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android性能之——线上帧率检测的实现

程序员文章站 2022-03-27 21:46:39
Android性能之——帧率检测本文我们来学习如何实现帧率的检测。为什么要检测帧率Android在设计的时候,把帧频限定在了每秒60帧,当我们的APP的帧频60fps时,画面就会非常的流程。但是通常由于各种各样的原因,帧频很可能会小于60fps,这样就会出现丢帧现象,用户端表现为可感知的卡顿等现象。那面我们的帧频可以高于60fps吗,答案是否定的,这是因为界面刷新渲染依赖底层的VSYNC信号,VSYNC信号以每秒60次的频率发送给上层,并且高于60fps的帧频也是没有必要的,因为人眼与大脑之间的协作...

Android性能之——帧率检测


本文我们来学习如何实现帧率的检测。

为什么要检测帧率

Android在设计的时候,把帧频限定在了每秒60帧,当我们的APP的帧频60fps时,画面就会非常的流程。但是通常由于各种各样的原因,帧频很可能会小于60fps,这样就会出现丢帧现象,用户端表现为可感知的卡顿等现象。那面我们的帧频可以高于60fps吗,答案是否定的,这是因为界面刷新渲染依赖底层的VSYNC信号,VSYNC信号以每秒60次的频率发送给上层,并且高于60fps的帧频也是没有必要的,因为人眼与大脑之间的协作无法感知超过60fps的画面更新。

12fps大概类似手动快速翻动书籍的帧率,这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。但是低于30fps是无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,当然超过60fps是没有必要的。

开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来处理所有的任务。

我们如何来获得应用的帧率呢?线下环境我们可以使用Systrace等工具来进行分析,或者也可以使用GPU呈现模式分析来检测丢帧卡顿等问题。现在,如果我们想要监控线上用户的在使用过程中,是否卡顿丢帧,想要知道APP真实环境的帧率是多少?如何来做呢?

线上帧率监控实现

想要实现线上用户的帧率监控,我们可以通过 Choreographer.FrameCallback 回调来实现帧率监控。

关于 Choreographer 的实现原理,请参考《从源码分析Choreographer是如何实现VSYNC信号的请求及帧的刷新处理?》

package com.budaye.simpledemo;

import android.util.Log;
import android.view.Choreographer;

/**
 * @ProjectName: SimpleDemo
 * @Desc:
 * @Author: buyuntao
 * @Date: 2020/11/11
 */
public class FpsTest implements Choreographer.FrameCallback {
    private long mLastFrameTimeNanos = 0; //最后一次时间
    private long mFrameTimeNanos = 0; //本次的当前时间
    private int mFpsCount = 0;

    public void startFps() {
        mLastFrameTimeNanos = System.nanoTime();
        Choreographer.getInstance().postFrameCallback(this);
        AsyncThreadTask.executeDelayed(runnable, 1000);
    }

    //定时任务
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            calculateFPS();
            AsyncThreadTask.executeDelayed(runnable, 1000);
        }
    };

    private void calculateFPS() {
        if (mLastFrameTimeNanos == 0) {
            mLastFrameTimeNanos = mFrameTimeNanos;
            return;
        }
        float costTime = (float) (mFrameTimeNanos - mLastFrameTimeNanos) / 1000000000.0F;//纳秒转成毫秒。
        if (mFpsCount <= 0 && costTime <= 0.0F) {
            return;
        }
        int fpsResult = (int) (mFpsCount / costTime);
        mLastFrameTimeNanos = mFrameTimeNanos;
        mFpsCount = 0;
        Log.d("budaye", "当前帧率为:" + fpsResult);
    }

    @Override
    public void doFrame(long frameTimeNanos) {
        mFpsCount++;
        mFrameTimeNanos = frameTimeNanos;
        //注册下一帧回调
        Choreographer.getInstance().postFrameCallback(this);
    }
}

  1. 使用线程,执行一个异步定时任务,每1000ms执行一次,用于统计1秒内的帧率。

  2. 使用 Choreographer.getInstance().postFrameCallback(this) 注册 VSYNC 信号回调监听,当 VSYNC 信号返回时,会执行 doFrame 回调函数。

  3. 在 doFrame 方法中,我们统计每秒内的执行次数,以及记录当前帧的时间,并注册一下次监听。

扩展:Android系统中的常用时间戳

在前文中,doFrame 参数返回的时间是纳秒,我们在计算中也涉及到了时间单位的转换。我们在开发中经常会遇到各种时间戳,那么在Android中,都有哪些时间戳呢?又有上面区别呢?

请参考《Android系统中的常用时间戳及时间单位》

ps:喜欢,就点个赞吧????~

本文地址:https://blog.csdn.net/u011578734/article/details/109627596