Android测量每秒帧数Frames Per Second (FPS)的方法

作者:红薯 时间:2022-01-21 05:43:15 

本文实例讲述了Android测量每秒帧数Frames Per Second (FPS)的方法。分享给大家供大家参考。具体如下:

MainThread.java:


package net.obviam.droidz;
import java.text.DecimalFormat;
import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;
/**
* @author impaler
*
* The Main thread which contains the game loop. The thread must have access to
* the surface view and holder to trigger events every game tick.
*/
public class MainThread extends Thread {
private static final String TAG = MainThread.class.getSimpleName();
// desired fps
private final static int MAX_FPS = 50;
// maximum number of frames to be skipped
private final static int MAX_FRAME_SKIPS = 5;
// the frame period
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
// Stuff for stats */
private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp
// we'll be reading the stats every second
private final static int STAT_INTERVAL = 1000; //ms
// the average will be calculated by storing
// the last n FPSs
private final static int FPS_HISTORY_NR = 10;
// last time the status was stored
private long lastStatusStore = 0;
// the status time counter
private long statusIntervalTimer = 0l;
// number of frames skipped since the game started
private long totalFramesSkipped   = 0l;
// number of frames skipped in a store cycle (1 sec)
private long framesSkippedPerStatCycle = 0l;
// number of rendered frames in an interval
private int frameCountPerStatCycle = 0;
private long totalFrameCount = 0l;
// the last FPS values
private double fpsStore[];
// the number of times the stat has been read
private long statsCount = 0;
// the average FPS since the game started
private double averageFps = 0.0;
// Surface holder that can access the physical surface
private SurfaceHolder surfaceHolder;
// The actual view that handles inputs
// and draws to the surface
private MainGamePanel gamePanel;
// flag to hold game state
private boolean running;
public void setRunning(boolean running) {
 this.running = running;
}
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
 super();
 this.surfaceHolder = surfaceHolder;
 this.gamePanel = gamePanel;
}
@Override
public void run() {
 Canvas canvas;
 Log.d(TAG, "Starting game loop");
 // initialise timing elements for stat gathering
 initTimingElements();
 long beginTime;  // the time when the cycle begun
 long timeDiff;  // the time it took for the cycle to execute
 int sleepTime;  // ms to sleep (<0 if we're behind)
 int framesSkipped; // number of frames being skipped
 sleepTime = 0;
 while (running) {
  canvas = null;
  // try locking the canvas for exclusive pixel editing
  // in the surface
  try {
   canvas = this.surfaceHolder.lockCanvas();
   synchronized (surfaceHolder) {
    beginTime = System.currentTimeMillis();
    framesSkipped = 0; // resetting the frames skipped
    // update game state
    this.gamePanel.update();
    // render state to the screen
    // draws the canvas on the panel
    this.gamePanel.render(canvas);
    // calculate how long did the cycle take
    timeDiff = System.currentTimeMillis() - beginTime;
    // calculate sleep time
    sleepTime = (int)(FRAME_PERIOD - timeDiff);
    if (sleepTime > 0) {
     // if sleepTime > 0 we're OK
     try {
      // send the thread to sleep for a short period
      // very useful for battery saving
      Thread.sleep(sleepTime);
     } catch (InterruptedException e) {}
    }
    while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
     // we need to catch up
     this.gamePanel.update(); // update without rendering
     sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
     framesSkipped++;
    }
    if (framesSkipped > 0) {
     Log.d(TAG, "Skipped:" + framesSkipped);
    }
    // for statistics
    framesSkippedPerStatCycle += framesSkipped;
    // calling the routine to store the gathered statistics
    storeStats();
   }
  } finally {
   // in case of an exception the surface is not left in
   // an inconsistent state
   if (canvas != null) {
    surfaceHolder.unlockCanvasAndPost(canvas);
   }
  } // end finally
 }
}
/**
 * The statistics - it is called every cycle, it checks if time since last
 * store is greater than the statistics gathering period (1 sec) and if so
 * it calculates the FPS for the last period and stores it.
 *
 * It tracks the number of frames per period. The number of frames since
 * the start of the period are summed up and the calculation takes part
 * only if the next period and the frame count is reset to 0.
 */
private void storeStats() {
 frameCountPerStatCycle++;
 totalFrameCount++;
 // check the actual time
 statusIntervalTimer += (System.currentTimeMillis() - statusIntervalTimer);
 if (statusIntervalTimer >= lastStatusStore + STAT_INTERVAL) {
  // calculate the actual frames pers status check interval
  double actualFps = (double)(frameCountPerStatCycle / (STAT_INTERVAL / 1000));
  //stores the latest fps in the array
  fpsStore[(int) statsCount % FPS_HISTORY_NR] = actualFps;
  // increase the number of times statistics was calculated
  statsCount++;
  double totalFps = 0.0;
  // sum up the stored fps values
  for (int i = 0; i < FPS_HISTORY_NR; i++) {
   totalFps += fpsStore[i];
  }
  // obtain the average
  if (statsCount < FPS_HISTORY_NR) {
   // in case of the first 10 triggers
   averageFps = totalFps / statsCount;
  } else {
   averageFps = totalFps / FPS_HISTORY_NR;
  }
  // saving the number of total frames skipped
  totalFramesSkipped += framesSkippedPerStatCycle;
  // resetting the counters after a status record (1 sec)
  framesSkippedPerStatCycle = 0;
  statusIntervalTimer = 0;
  frameCountPerStatCycle = 0;
  statusIntervalTimer = System.currentTimeMillis();
  lastStatusStore = statusIntervalTimer;
//   Log.d(TAG, "Average FPS:" + df.format(averageFps));
  gamePanel.setAvgFps("FPS: " + df.format(averageFps));
 }
}
private void initTimingElements() {
 // initialise timing elements
 fpsStore = new double[FPS_HISTORY_NR];
 for (int i = 0; i < FPS_HISTORY_NR; i++) {
  fpsStore[i] = 0.0;
 }
 Log.d(TAG + ".initTimingElements()", "Timing elements for stats initialised");
}
}

希望本文所述对大家的java程序设计有所帮助。

标签:Android,帧数
0
投稿

猜你喜欢

  • 关于springboot2.4跨域配置问题

    2022-05-01 17:02:15
  • C#使用符号表实现查找算法

    2022-08-07 01:16:45
  • 一种类似JAVA线程池的C++线程池实现方法

    2021-11-02 21:31:52
  • MyBatis中的模糊查询语句

    2022-09-30 03:36:59
  • Android XUtils3框架的基本使用方法(二)

    2021-08-03 16:32:45
  • Android集成微信登录的步骤详解

    2023-01-12 15:12:45
  • mybatis批量添加,批量更新之前如何判断是否已经存在

    2022-01-03 20:33:38
  • 深入HRESULT与Windows Error Codes的区别详解

    2023-10-16 15:19:42
  • SpringBoot 过滤器 Filter使用实例详解

    2021-11-08 13:46:00
  • HashMap 和 HashSet的区别

    2023-01-05 22:45:30
  • Java面向对象的封装你了解吗

    2023-11-06 16:32:38
  • Android稳定性:可远程配置化的Looper兜底框架

    2022-02-18 09:02:23
  • C#中字符串编码处理

    2023-10-03 09:56:12
  • Java使用RedisTemplate如何根据前缀获取key列表

    2023-03-05 01:50:40
  • Android 基于百度语音的语音交互功能(推荐)

    2021-08-22 01:26:38
  • Android编程实现二维码的生成与解析

    2021-12-08 23:13:15
  • c# Linq查询详解

    2023-05-23 20:43:50
  • SpringBoot集成MybatisPlus报错的解决方案

    2022-06-28 05:03:20
  • C#实现餐厅管理系统

    2023-11-27 16:05:05
  • java split()使用方法解析

    2023-10-18 01:59:23
  • asp之家 软件编程 m.aspxhome.com