我对 async/await 的理解是,我的异步方法可以在不同的线程中执行,并且不会影响我的应用程序的响应能力。
我实现了一个简单的备份/恢复机制,其中的操作可能需要相当长的时间。在操作进行时,我想显示一个简单的等待指示器。因此我实现了以下内容(取自此处):
showDialog(context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return PopScope(....);
});
await Future.delayed(const Duration(seconds: 2));
if (!context.mounted) return;
Navigator.of(context).pop();
只要我不await Future.delayed(const Duration(seconds: 2));
使用某些真正消耗 CPU 的方法替换,这个方法就会很有效,例如await extractFileToDisk
。
如果我这样做,对话框要么
- 根本不显示(或者仅在操作完成后几毫秒内可见)或
- 如果我保持这个状态
Future.delay
一秒钟,一旦 CPU 消耗操作开始,等待指示器就会冻结。
我个人更倾向于将新的(对话框)小部件推送到 Navigator 堆栈并在那里进行处理 - 这样我就可以setState
根据进度更新对话框状态()。但我还没有找到这样的例子 - 而且我不确定这是否是正确的方向。
为什么我会遇到这些 GUI 冻结问题 - 以及如何最好地解决它?
您需要明确启动一个新线程,这样有望解决问题。但是,考虑到您的硬件资源有限,您异步调用的操作可能会耗尽您拥有的所有资源。当然,如果操作与您的硬件分开,即在位于其他地方的远程计算机上并通过 API 访问,那么您就不会遇到这样的问题。
因此,问题在于您的主线程和资源密集型操作都在同一台机器上运行。您可以应用一个隔离,它将拥有自己分配的内存和调用堆栈,因此,如果您的处理器密集型操作不会导致您拥有的所有处理器核心出现峰值,那么您的主 UI 将正常运行。