[029]如何获取屏幕帧率

2020-02-27  本文已影响0人  王小二的技术栈

前言

王小二图解Android【006】高帧率屏幕这期的视频中,我给大家揭秘今年所有安卓旗舰都会吹的高帧率屏幕,其实高帧率屏幕不需要应用开发人员去主动适配,只要应用能在当前的硬件配置下,规定时间(1s/屏幕帧率)中完成一帧的绘制就可以了。

那肯定有人就要问了,能否当前获得屏幕帧率,然后对高帧率屏幕做针对性优化,在有限的时间内完成一帧的绘制。

一、标准SDK接口

很简单,只要能够拿到WindowManager就可以获取。

//this是Activity
Log.v("Kobe", "Screen Hz is " + this.getWindowManager().getDefaultDisplay().getRefreshRate());
02-26 23:31:50.526 18982 18982 V Kobe    : Screen Hz is 60.000004

二、帧率约等于 1s/两次Vsync时间差

public class MainActivity extends AppCompatActivity {

    private long firstVsync;
    private long secondVsync;

    private Choreographer.FrameCallback firstCallBack = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            firstVsync = frameTimeNanos;
            Choreographer.getInstance().postFrameCallback(secondCallBack);
        }
    };

    private Choreographer.FrameCallback secondCallBack = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            secondVsync = frameTimeNanos;
            //1s = 1000000000ns
            long hz = 1000000000 / (secondVsync - firstVsync);
            Log.v("Kobe", "Screen Hz is " + hz);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        HandlerThread vSyncThread = new HandlerThread("Vsync");
        vSyncThread.start();
        Handler handler = new Handler(vSyncThread.getLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                Choreographer.getInstance().postFrameCallback(firstCallBack);
            }
        });
    }
}

原理就是利用Choreographer这个类的postFrameCallback的方法。调用postFrameCallback之后将会在下一个Vsync信号来的时候触发运行FrameCallback的doFrame,Vsync的上报时间就是形参frameTimeNanos(单位:纳秒)。

long hz = 1000000000 / (secondVsync - firstVsync);

简单的计算就可以算出来了。

02-26 23:38:01.633 19234 19261 V Kobe    : Screen Hz is 59//大概的推测出是60hz的屏幕

有没有发现上述代码中的两个细节

1.Choreographer.getInstance()必须运行在有Looper的线程中。

因为Vsync信号的监听是通过Looper中的epoll机制监听的。

2.我没有使用主线程的Looper,而是另外新建HandlerThread。

因为主线程的Looper比较忙,容易导致Vsync信号监听推迟,导致两次Vsync时间差不对。
我之前没有另外新建HandlerThread,得到的结果是不固定的,而且是错的。

02-26 23:22:29.374 18442 18442 V Kobe    : Screen Hz is 14
02-26 23:31:21.079 18753 18753 V Kobe    : Screen Hz is 19
如果听不懂,可以看我的视频

王小二图解Android【001】Looper上篇
王小二图解Android【002】Looper下篇

三、总结

一般来说用标准SDK接口就够了,为什么我要大费周章的讲方法2,其实是想让大家了解Choreographer的作用,因为在我们调用View的渲染中就是用到了这个类,在下一个Vsync信号到来的时候触发渲染的代码。

思考

如果你们有其他想法可以获得屏幕的帧率,也可以回复留言。

上一篇 下一篇

猜你喜欢

热点阅读