【问题标题】:Android: How to find the frame rate of a device?Android:如何查找设备的帧速率?
【发布时间】:2026-01-11 14:55:02
【问题描述】:

帧速率:我指的是显示变化的速率。即调用 Ondraw() 并重新绘制画布。

所有安卓设备都有默认费率吗?由于这个速率取决于设备的处理能力,在开始为该移动设备编程之前,如何找出设备的帧速率?

【问题讨论】:

  • 我们是在谈论 GL 表面,还是在一般情况下(如使用动画时)?没有默认帧率,我可以提前说。
  • 只是说二维动画!使用表面视图

标签: android


【解决方案1】:

这可能是this question 的后续行动,我在其中建议有一个不断重复绘制的重绘循环可能有点过分。可能有一个 api 可以找出设备显示的功能,但如果有我不知道。当您编写自己的事件循环/线程函数时,您可以通过调用“绘制”方法的频率来控制帧速率。通常情况下,我认为对于大多数用途来说,刷新率为 30 左右就可以了。如果您正在编写一个需要快速动画的快速动作游戏,那么您可能希望尽可能快地运行,fps 越多,它就会越流畅。

一个典型的事件循环(线程运行函数)可能看起来像这样:

// define the target fps
private static final int UPDATE_RATE = 30;  // Frames per second (fps)

public void run() {
     while(running) {  // volatile flag, set somewhere else to shutdown
         long beginTimeMillis, timeTakenMillis, timeLeftMillis;

         // get the time before updates/draw
         beginTimeMillis = System.currentTimeMillis();  

         // do the thread processing / draw
         performUpdates();  // move things if required
         draw();            // draw them on the screen

         // get the time after processing and calculate the difference
         timeTakenMillis = System.currentTimeMillis() - beginTimeMillis;

         // check how long there is until we reach the desired refresh rate
         timeLeftMillis = (1000L / UPDATE_RATE) - timeTakenMillis;

         // set some kind of minimum to prevent spinning
         if (timeLeftMillis < 5) { 
             timeLeftMillis = 5; // Set a minimum
         }

         // sleep until the end of the current frame    
         try {
             TimeUnit.MILLISECONDS.sleep(timeLeftMillis);  
         } catch (InterruptedException ie) {
         }
    }
}

【讨论】:

  • 恐怕这不是一个好主意,原因并不那么明显:如果手机的显示更新速率不是 30 的倍数(例如,48,比如Doogee X20L),则动画将不流畅。这是因为无论如何都会显示 48 个帧,但只有 30 个不同的帧(由您的代码提供),这意味着其中一些会在 1/48 秒内可见,而有些会在 2/48 秒内可见。这会导致一种紧张的效果,让您认为“这里有问题,但我无法真正解释”。
【解决方案2】:

您可以使用Android提供的dumpsys工具。要获取有关设备显示的信息,请执行以下命令:

adb shell dumpsys display

设备的帧率信息在属性“mPhys”中提供。

你会发现类似的东西:

mPhys=PhysicalDisplayInfo{1080x1920, 60.000004 fps, densitiy 3.0, 
480.0x480.0 dpi, secure true}

设备的帧速率在第二个字段中,在我的例子中是 60.000004 fps

【讨论】:

  • 这是正确答案。您在此处获得的 FPS 是您在该设备上能够达到的最大值,无论您是在 SurfaceView(循环中)或硬件 OpenGL 上使用画布上的软件绘图(使用 lockCanvas())在GLSurfaceView 上渲染(在onDrawFrame() 中)。我认为理想情况下这个值应该是 60(Google 的建议是在 developer.android.com/training/testing/performance.html 中瞄准),但它可能会更低(例如,在全新的 Doogee X20L 上它是 47.24)。我还没有见过比它更高的手机。在华为 P9 Lite 或 Moto X 上是 60。
【解决方案3】:

您不能依赖特定的帧速率。 Android是一个使用多任务的操作系统。如果后台有一些线程在做一些繁重的工作,你可能无法达到你想要的帧率。即使您是唯一的活动进程,帧速率也取决于您的 GPU 和 CPU,以及每个进程的时钟。也许用户有一个被黑的 ROM,可以将时钟更改为自定义值。

某些手机可能被锁定到特定的帧速率。 HTC EVO 最长时间被锁定在 30fps,直到定制 ROM 的出现消除了这一限制。较新的 EVO ROM 也消除了这一限制。

我不知道您要做什么,但最好的办法是测量每一帧之后的时间,并将该增量用于您的动画。如果您尝试显示 FPS,请使用平滑平均值。

【讨论】:

    【解决方案4】:

    这可能是一个老问题,但为了将来参考,我发现了这个名为 Takt 的库 https://github.com/wasabeef/Takt。 Takt 是用于使用 Choreographer 测量 FPS 的 Android 库。

    【讨论】:

      【解决方案5】:

      有一种在运行时查找设备 FPS 的简单方法。

      只需调用以下方法:

      long oneSecondLater=0;
      int FPS=0;
      int counter=0;
      ValueAnimator v_animator;
      private void logFPS()
      {
          oneSecondLater = System.currentTimeMillis()+1000;
          v_animator = ValueAnimator.ofFloat(0.0f, 1.0f);
          v_animator.setRepeatCount(ValueAnimator.INFINITE);
          v_animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator animation) {
                  FPS++;
                  if(System.currentTimeMillis() > oneSecondLater)
                  {
                      counter++;
                      if(counter>1)//ignore the first onAnimationUpdate call (it is not correct)
                          Log.i("checkFPS","FPS:" + FPS);
                      FPS=0;
                      oneSecondLater = System.currentTimeMillis()+1000;
                  }
              }
          });
          v_animator.start();
      }
      

      我每秒记录一次 FPS,我的 Logcat 的输出如下

      因为对于ValueAnimator,onAnimationUpdate()方法会根据设备FPS调用;

      【讨论】: