我正在开发一个捕获和处理图像的应用程序。该代码的简化版本是:
build() {
return FloatingActionButton(
onPressed: processImage,
child: Icon(
Icons.camera_alt,
color: color,
),
);
}
processImage(Camera image) async {
await image.process();
}
在另一堂课中:
Future<image> process() {
return Future(() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
//process image
}
}
});
}
但是当process()
运行时,UI冻结。
为什么会这样?该函数不是传递给在后台运行的Future构造函数吗?
答案 0 :(得分:1)
由于Dart使用事件循环,因此所有代码(同步和异步)将仅在相同的时间isolate
(在其他语言中,将thread
作为类推)运行。这样,当process
方法出队并执行时,尽管是异步的,但仍会由于较长的执行时间而阻塞线程并导致丢弃帧。解决该问题的最佳方法是在新线程中生成另一个隔离,然后在那里进行计算。 Flutter为这种确切的用例提供了一种方便的方法,称为compute
。它使用一个顶级函数(不是在类中,也不是匿名的)可以将原始类型参数(包括Map
和List
)作为参数,并将在将来的某个时刻返回。有关compute
的更多信息,请参见上面链接的文档。
如果您需要将多个参数传递给compute
,则一种通用模式(不只是此用例)正在制定一种将类的字段序列化为Map<String, dynamic>
的方法,并且从Map<String, dynamic>
创建对象的工厂构造函数。通过反射,此过程会更容易,但是Flutter出于性能原因将其禁用。
有关Flutter文档中compute
的完整示例,请参见此处:https://flutter.dev/docs/cookbook/networking/background-parsing
答案 1 :(得分:0)
您可以将间隙插入事件循环。
简单方法:
Future<image> process2() {
return Future(() async {
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
// process
}
if (x % 100 == 0) {
await Future.delayed(Duration(seconds: 100));
}
}
});
}