在AIR应用程序中,我有以下代码:
theDialog = PopUpManager.createPopUp(this,TheDialogClass,true)为TheDialogClass; theDialog.addEventListener(FlexEvent.CREATION_COMPLETE,cpuIntensiveCalc);
在cpuIntensiveCalc结束时,将删除该对话框。该对话框通知用户“正在发生的事情,请等待。”
问题是cpuIntensiveCalc在对话框绘制之前启动。因此,用户体验是应用程序在没有指示器的情况下冻结10秒钟,然后模式对话框在屏幕上快速闪烁(不到一秒钟)。
Adobe文档说这是关于creation_complete
组件完成构建后调度, 物业处理,测量,布局和绘图。
所以这感觉就像是正确的事件 在完整性的名义,我也试过
theDialog = PopUpManager.createPopUp(this,TheDialogClass,true)为TheDialogClass; cpuIntensiveCalc();
但结果相同。
TIA
答案 0 :(得分:1)
原因是Flash Player是单线程的,因此您阻止UI对Dialog Popup做出反应,直到数学块完成。
Hacky修复时间......
您有两种选择。
(这个应该可以工作,但是未经测试)在callLater中包装cpuIntensiveCalc()调用,以便在阻止渲染之前UI可以完成渲染。
或者
使用“绿色线程”来分解您的处理,这样您就不会完全阻止UI处理。 Take a look
答案 1 :(得分:1)
(我刚才有同样的问题=>即使这个帖子已经老了,我只想提供我的解决方案)
(免责声明:这有点难看,但他们说在UI层中没问题...... ;-))
Flex是单线程的(至少从我们的开发人员的角度来看,我认为VM背后的场景线程)
=>在用户对窗口小部件执行某些操作后,通常在UI线程中执行代码。任何更新UI组件的调用(如setProgress或setLabel)都只会在渲染周期结束时在屏幕上呈现(再次参见UiComponent生命周期)。
=>在callLater中调用“cpuIntensiveCalc”会让框架在执行方法之前显示弹出窗口。
在实践中,我注意到在显示弹出窗口之前,您通常必须拥有几个UI循环,如下所示:
new MuchLaterRunner(popup, 7, cpuIntensiveCalc).runLater();
MuchLaterRunner的定义如下:
public class MuchLaterRunner
{
var uiComp:UIComponent;
var currentCounter = 0;
var cyclesToWaitBeforeExecution=0;
var command:Function;
public function MuchLaterRunner(uiComp:UIComponent, cyclesToWaitBeforeExecution:uint, command:Function)
{
this.uiComp = uiComp;
this.command = command;
this.cyclesToWaitBeforeExecution =cyclesToWaitBeforeExecution;
}
public function runLater() {
currentCounter ++;
if (currentCounter >= cyclesToWaitBeforeExecution) {
uiComp.callLater(command);
} else {
// wait one more cycle...
uiComp.callLater(runLater);
}
}
}
之后调用setProgress时的问题是相同的:我们必须将cpuIntensiveCalc分成可在每个UI周期运行的小型可调用方法,否则进度条不会,错误,进展。
答案 2 :(得分:0)
在弹出窗口中使用enterFrame事件。不要忘记在enterFrame事件处理程序中删除侦听器 - 否则将在每个帧中调用cpu密集型方法,从而导致应用程序崩溃。如果这首先不起作用,请使用专用号码作为计数器,并在输入帧处理程序中继续增加它 - 仅当计数器达到适当的值时才调用cpu heavy方法。通过跟踪和错误找到“适当的”值。
theDialog = PopUpManager.createPopUp(this, TheDialogClass, true) as TheDialogClass;
theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(e:Event):void
{
//can use theDialog instead of e.currentTarget here.
(e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
cpuIntensiveCalc();
}
//in case the above method doesn't work, do it the following way:
theDialog.addEventListener(Event.ENTER_FRAME, onEnterFrame);
private var _frameCounter:Number = 0;
private function onEnterFrame(e:Event):void
{
_frameCounter++;
var desiredCount:Number = 1;//start with one - increment until it works.
if(_frameCounter < desiredCount)
return;
//can use theDialog instead of e.currentTarget here.
(e.currentTarget).removeEventListener(Event.ENTER_FRAME, onEnterFrame);
cpuIntensiveCalc();
}