Flutter 颤振如何向用户显示FPS(每秒帧数)?

Flutter 颤振如何向用户显示FPS(每秒帧数)?,flutter,dart,Flutter,Dart,有没有办法在颤振中向用户显示FPS aka Frame per second?有什么小部件或软件包吗 注意: 我不是在测试期间要求FPS 作为如何在Dart中构建FRP(功能反应程序)的一个示例,我决定尝试构建一个FPS计数器——也就是说,一个用于确定正在运行的应用程序的帧速率的实用程序。 导入'dart:async'; ///返回每个[animationFrame]激发的[Stream]。 /// ///可以提供一个函数,该函数返回在下一个 ///可用帧。例如,在浏览器环境中,这可能会被委派

有没有办法在颤振中向用户显示FPS aka Frame per second?有什么小部件或软件包吗

注意:


我不是在测试期间要求FPS

作为如何在Dart中构建FRP(功能反应程序)的一个示例,我决定尝试构建一个FPS计数器——也就是说,一个用于确定正在运行的应用程序的帧速率的实用程序。

导入'dart:async';
///返回每个[animationFrame]激发的[Stream]。
///
///可以提供一个函数,该函数返回在下一个
///可用帧。例如,在浏览器环境中,这可能会被委派
///到“window.animationFrame”:
///
/// ```
///每个帧(animationFrame:()=>window.animationFrame)
/// ```
流式处理每个帧({Future animationFrame():nextFrame});
确定每秒帧数意味着我想在我的应用程序中的零星时刻检查我上次能够检查的时间有多长了。假设如下: 渲染通常以秒为单位,或者以适合的帧数为单位 1000毫秒(ms)是1秒 渲染帧所需的时间是两个时间戳之间的差 我们可以从每个“帧”发出一个时间戳开始

在Dart中,它是单线程的,基于一个事件循环,我们假设如果我们能够至少每一次(空闲时间)控制一次事件循环,那么之前的所有工作都是有效的帧

我很天真地尝试实现它-我创建了一个新的StreamController,并使用Future.delayed(它在所有平台上都委托一个计时器)来通知下一帧的时间:

    import 'dart:async';

/// A cross-platform implementation for requesting the next animation frame.
///
/// Returns a [Future<num>] that completes as close as it can to the next
/// frame, given that it will attempt to be called 60 times per second (60 FPS)
/// by default - customize by setting the [target].
Future<num> nextFrame([num target = 60]) {
  final current = new DateTime.now().millisecondsSinceEpoch;
  final call = math.max(0, (1000 ~/ target) - (current - _previous));
  return new Future.delayed(
    new Duration(milliseconds: call),
    () => _previous = new DateTime.now().millisecondsSinceEpoch,
  );
}

/// Returns a [Stream] that fires every [animationFrame].
///
/// May provide a function that returns a future completing in the next
/// available frame. For example in a browser environment this may be delegated
/// to `window.animationFrame`:
///
/// ```
/// eachFrame(animationFrame: () => window.animationFrame)
/// ```
Stream<num> eachFrame({Future<num> animationFrame(): nextFrame}) {
  StreamController<num> controller;
  var cancelled = false;
  void onNext(num timestamp) {
    if (cancelled) return;
    controller.add(timestamp);
    animationFrame().then(onNext);
  }
  controller = new StreamController<num>(
    sync: true,
    onListen: () {
      animationFrame().then(onNext);
    },
    onCancel: () {
      cancelled = true;
    },
  );
  return controller.stream;
}
注意:这并不总是准确的-特别是在web上,我们可以用window.animationFrame做得更好,但我还是想要一个可以跨平台开箱即用的东西

好的,我需要计算并输出每秒的帧数,而不是添加时间戳。我本可以内联完成这项工作,但为了使其更具可扩展性,我通过一个简单的StreamTransformer实现了它,这是我可以通过transform在任何流之上使用的代码:

/// Computes frames-per-second given a [Stream<num>] of timestamps.
///
/// The resulting [Stream] is capped at reporting a maximum of 60 FPS.
///
/// ```
/// // Listens to FPS for 10 frames, and reports at FPS, printing to console.
/// eachFrame()
///   .take(10)
///   .transform(const ComputeFps())
///   .listen(print);
/// ```
class ComputeFps implements StreamTransformer<num, num> {
  final num _filterStrength;

  /// Create a transformer.
  ///
  /// Optionally specify a `filterStrength`, or how little to reflect temporary
  /// variations in FPS. A value of `1` will only keep the last value.
  const ComputeFps([this._filterStrength = 20]);

  @override
  Stream<num> bind(Stream<num> stream) {
    StreamController<num> controller;
    StreamSubscription<num> subscription;
    num frameTime = 0;
    num lastLoop;
    controller = new StreamController<num>(
      sync: true,
      onListen: () {
        subscription = stream.listen((thisLoop) {
          if (lastLoop != null) {
            var thisFrameTime = thisLoop - lastLoop;
            frameTime += (thisFrameTime - frameTime) / _filterStrength;
            controller.add(math.min(1000 / frameTime, 60));
          }
          lastLoop = thisLoop;
        });
      },
      onCancel: () => subscription.cancel(),
    );
    return controller.stream;
  }
}
我现在得到如下输出:

六十 60 60 60 60 60 60 60 六十

看起来不错!我已经


屏幕截图:


代码:

我不知道是否有一个软件包可以帮助您不断向用户显示FPS,但如果您想手动执行,可以尝试以下方法:

class\u FpsPageState扩展状态{
bool _shouldCount=false;
var _计数=0;
@凌驾
小部件构建(构建上下文){
如果(_shouldCount)_count++;
返回脚手架(
正文:中(
儿童:升降按钮(
已按下:(){
_shouldCount=true;
_计数=0;
计时器周期(持续时间(毫秒:1),(计时器){
设置状态(){
如果(timer.tick>=1000){
timer.cancel();
_shouldCount=false;
}
});
});
},
子项:文本(_count!=0?'FPS:$_count':'START'),
),
),
);
}
}
这是一个很好的演示:
/// Computes frames-per-second given a [Stream<num>] of timestamps.
///
/// The resulting [Stream] is capped at reporting a maximum of 60 FPS.
///
/// ```
/// // Listens to FPS for 10 frames, and reports at FPS, printing to console.
/// eachFrame()
///   .take(10)
///   .transform(const ComputeFps())
///   .listen(print);
/// ```
class ComputeFps implements StreamTransformer<num, num> {
  final num _filterStrength;

  /// Create a transformer.
  ///
  /// Optionally specify a `filterStrength`, or how little to reflect temporary
  /// variations in FPS. A value of `1` will only keep the last value.
  const ComputeFps([this._filterStrength = 20]);

  @override
  Stream<num> bind(Stream<num> stream) {
    StreamController<num> controller;
    StreamSubscription<num> subscription;
    num frameTime = 0;
    num lastLoop;
    controller = new StreamController<num>(
      sync: true,
      onListen: () {
        subscription = stream.listen((thisLoop) {
          if (lastLoop != null) {
            var thisFrameTime = thisLoop - lastLoop;
            frameTime += (thisFrameTime - frameTime) / _filterStrength;
            controller.add(math.min(1000 / frameTime, 60));
          }
          lastLoop = thisLoop;
        });
      },
      onCancel: () => subscription.cancel(),
    );
    return controller.stream;
  }
}
import 'package:fps/fps.dart';

void main() {
  eachFrame()
    .take(10)
    .transform(const ComputeFps())
    .listen(print);
}