我使用dart FFI从本机端检索数据,并用抖动CustomPaint
显示数据。
我使用ValueNotifier
控制CustomPaint
的重绘。
使用状态类,我定期从本机端轮询数据,并将其分配给ValueNotifier
。
class _ColorViewState extends State<ColorView> {
ValueNotifier<NativeColor> _notifier;
Timer _pollTimer;
@override
void initState() {
// TODO: implement initState
super.initState();
ffiInit();
// initialize notifier
_notifier = ValueNotifier<NativeColor>(ffiGetColor().ref);
_pollTimer = Timer.periodic(Duration(milliseconds: 16), _pollColor);
}
_pollColor(Timer t) {
setState(() {
print('polling ...');
_notifier.value = ffiGetColor().ref;
print('polled: ${_notifier.value.r}, ${_notifier.value.g}, ${_notifier.value.b}');
});
}
....
}
请注意,我的轮询速度约为60fps。
然后将通知程序绑定到CustomPaint重绘
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
width: double.infinity,
height: double.infinity,
color: widget.clrBackground,
child: ClipRect(
child: CustomPaint(
painter: _ColorViewPainter(
context: context,
notifier: _notifier,
clrBackground: Color.fromARGB(255, 255, 0, 255)
)
)
)
);
}
然后将CustomPaint的重绘绑定到ValueNotifier
,我用检索到的颜色绘制屏幕。
class _ColorViewPainter extends CustomPainter {
ValueNotifier<NativeColor> notifier;
BuildContext context;
Color clrBackground;
_ColorViewPainter({this.context, this.notifier, this.clrBackground})
: super(repaint: notifier) {
}
@override
bool shouldRepaint(_ColorViewPainter old) {
print('should repaint');
return true;
}
@override
void paint(Canvas canvas, Size size) {
print("paint: start");
final r = notifier.value.r;
final g = notifier.value.g;
final b = notifier.value.b;
print("color: $r, $g, $b");
final paint = Paint()
..strokeJoin = StrokeJoin.round
..strokeWidth = 1.0
..color = Color.fromARGB(255, r, g, b)
..style = PaintingStyle.fill;
final width = size.width;
final height = size.height;
final content = Offset(0.0, 0.0) & Size(width, height);
canvas.drawRect(content, paint);
print("paint: end");
}
}
然后,我注意到从视觉上看颜色更新的速度低于轮询。尽管可以重涂,但可以通过同时查看我的日志记录和电话屏幕来观察到这一点。
我应该如何实现感知到的同步更新?
我还应该补充一点,本地后端模拟以1秒的间隔在红色/绿色/蓝色之间切换颜色。
由于轮询的频率要高得多,因此我希望每隔1秒就能看到一个相当稳定的颜色变化。但是现在,颜色以更长的时间间隔改变。有时很少重涂,这可能需要几秒钟的时间,而轮询总是返回相当稳定的数据更新。
根据我的测试,我应该保留setState
,否则重新绘制只会停止。通过将数据更新切换到飞镖地,我发现一切都按预期进行。因此,它必须在本机端或FFI接口中。这是经过修改的dart代码,在不涉及FFI的情况下可以正常工作。
基本上,我使用恒定的颜色集合并对其进行迭代。
class _ColorViewState extends State<ColorView> {
ValueNotifier<NativeColor> _notifier;
Timer _pollTimer;
var _colors;
int _step = 0;
@override
void initState() {
// TODO: implement initState
super.initState();
ffiInit();
// constant colour collection
_colors = [
[255, 0, 0],
[0, 255, 0],
[0, 0, 255]
];
_notifier = ValueNotifier<NativeColor>(ffiGetColor().ref);
_pollTimer = Timer.periodic(Duration(milliseconds: 1000), _pollColor);
}
_pollColor(Timer t) {
setState(() {
print('polling ...');
// _notifier.value = ffiGetColor().ref;
_notifier.value.r = _colors[_step][0];
_notifier.value.g = _colors[_step][1];
_notifier.value.b = _colors[_step][2];
print('polled: ${_notifier.value.r}, ${_notifier.value.g}, ${_notifier.value.b}');
if (++_step >= _colors.length) {
_step = 0;
}
});
}
在本机方面,我有一个生产者/消费者线程模型。生产者以固定的速率循环浏览颜色集合。消费者只要受到生产者的检查就可以得到它。
#include <cstdlib>
#include <ctime>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
#ifdef __cplusplus
#define EXTERNC extern "C" __attribute__((visibility("default"))) __attribute__((used))
#else
#define EXTERNC
#endif // #ifdef __cplusplus
struct NativeColor {
int r;
int g;
int b;
};
NativeColor* gpColor = nullptr;
NativeColor gWorker = {255, 0, 255};
// producer / consumer thread tools
std::thread gThread;
std::mutex gMutex;
std::condition_variable gConVar;
int gColors[][3] = {
{255, 0, 0},
{0, 255, 0},
{0, 0, 255}
};
int gCounter = 0;
int gCounterPrev = 0;
EXTERNC void ffiinit() {
if(!gpColor) {
gpColor = (struct NativeColor*)malloc(sizeof(struct NativeColor));
}
if(!gThread.joinable()) {
gThread = std::thread([&]() {
while(true) {
std::this_thread::sleep_for (std::chrono::seconds(1));
std::unique_lock<std::mutex> lock(gMutex);
gWorker.r = gColors[gCounter][0];
gWorker.g = gColors[gCounter][1];
gWorker.b = gColors[gCounter][2];
if(++gCounter == 3) {
gCounter = 0;
gCounterPrev = gCounter;
}
lock.unlock();
gConVar.notify_one();
}
});
}
}
EXTERNC struct NativeColor* ffiproduce() {
// get yellow
gpColor->r = 255;
gpColor->g = 255;
gpColor->b = 255;
std::unique_lock<std::mutex> lock(gMutex);
gConVar.wait(lock, [&]{
return gCounter > gCounterPrev;
//return true;
});
*gpColor = gWorker;
gCounterPrev = gCounter;
lock.unlock();
return gpColor;
}
ffiproduce()
绑定到飞镖端ffiGetColor()
函数。因此,我假设此使用者函数在主线程中起作用。
所以我有一个想法,就是C ++端的线程协调可能会影响CustomPaint
上的抖动渲染方式。
但是我不知道如何证明这一点。
答案 0 :(得分:0)
我通过使用本机端的睡眠功能取得了一些进步。
这是我的发现:
因此,我相信我的数据生成模型必须适应抖动,以确保轮询不会阻塞或以抖动的首选速率(例如60fps)附近的速率传递。