当前位置: 移动技术网 > 移动技术>移动开发>Android > Android性能之——线上帧率检测的实现

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

2020年11月11日  | 移动技术网移动技术  | 我要评论
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

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网