有什么办法可以在Flutter中向用户显示每秒FPS aka帧?是否有任何小部件或软件包?
注意:
我在测试期间不需要FPS。
最佳答案
作为如何在Dart中构建FRP(功能性反应程序)的示例,我决定尝试构建FPS计数器-即,用于确定正在运行的应用程序的帧速率的实用程序。
import 'dart:async';
/// 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});
确定每秒帧数意味着我想在应用程序中偶尔检查一下自上次检查以来已经过了多长时间。假设以下内容:
渲染通常以秒或适合多少帧为单位
1000毫秒(ms)是一秒
渲染帧所需的时间是两个时间戳之间的差
我们可以从每个“帧”发出一个时间戳开始
我尝试过天真地实现它-创建了一个新的StreamController,并使用Future.delayed(在所有平台上都委派给Timer)来通知下一帧的时间:
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;
}
import 'package:fps/fps.dart';
/// Prints 10 timestamps, each printed ~every 13.33ms.
void main() {
eachFrame().take(10).listen(print);
}
好的,因此除了添加时间戳之外,我还需要计算和输出每秒的帧数。我可以内联完成此操作,但为了使其更具扩展性,我通过一个简单的StreamTransformer实现了该代码,可以通过转换在任何Stream的顶部使用该代码:
/// 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);
}
我现在得到这样的输出:
看起来挺好的!我included the source code and an example repo on github.
original